Repository: stashapp/stash-box Branch: master Commit: 5e4bbf1cb9e3 Files: 752 Total size: 5.0 MB Directory structure: gitextract_6obqz5rx/ ├── .dockerignore ├── .gitattributes ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ ├── discussion---request-for-commentary--rfc-.md │ │ └── feature_request.md │ └── workflows/ │ ├── build.yml │ ├── frontend-lint.yml │ └── golangci-lint.yml ├── .gitignore ├── .golangci.yml ├── CLAUDE.md ├── LICENSE ├── Makefile ├── README.md ├── cmd/ │ └── stash-box/ │ ├── init.go │ └── main.go ├── docker/ │ ├── build/ │ │ └── x86_64/ │ │ ├── Dockerfile │ │ ├── db/ │ │ │ └── initdb.sh │ │ └── docker-compose.yml │ ├── ci/ │ │ └── x86_64/ │ │ ├── Dockerfile │ │ └── docker_push.sh │ └── production/ │ ├── docker-compose.yml │ └── postgres/ │ └── Dockerfile ├── frontend/ │ ├── .gitattributes │ ├── .gitignore │ ├── .nvmrc │ ├── README.md │ ├── biome.json │ ├── codegen.yml │ ├── embed.go │ ├── index.html │ ├── package.json │ ├── src/ │ │ ├── App.scss │ │ ├── App.tsx │ │ ├── Login.tsx │ │ ├── Main.tsx │ │ ├── components/ │ │ │ ├── amendableEditCard/ │ │ │ │ ├── AmendableChangeRow.tsx │ │ │ │ ├── AmendableImageChangeRow.tsx │ │ │ │ ├── AmendableLinkedChangeRow.tsx │ │ │ │ ├── AmendableListChangeRow.tsx │ │ │ │ ├── AmendableModifyEdit.tsx │ │ │ │ ├── AmendableURLChangeRow.tsx │ │ │ │ ├── AmendmentContext.tsx │ │ │ │ └── index.ts │ │ │ ├── changeRow/ │ │ │ │ ├── ChangeRow.tsx │ │ │ │ └── index.ts │ │ │ ├── checkboxSelect/ │ │ │ │ ├── CheckboxSelect.tsx │ │ │ │ ├── index.ts │ │ │ │ └── styles.scss │ │ │ ├── deleteButton/ │ │ │ │ ├── DeleteButton.tsx │ │ │ │ └── index.ts │ │ │ ├── editCard/ │ │ │ │ ├── AddComment.tsx │ │ │ │ ├── EditCard.tsx │ │ │ │ ├── EditComment.tsx │ │ │ │ ├── EditExpiration.tsx │ │ │ │ ├── EditHeader.tsx │ │ │ │ ├── EditStatus.tsx │ │ │ │ ├── ModifyEdit.tsx │ │ │ │ ├── VoteBar.tsx │ │ │ │ ├── Votes.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── renderEntity.tsx │ │ │ │ └── styles.scss │ │ │ ├── editImages/ │ │ │ │ ├── editImages.tsx │ │ │ │ ├── index.ts │ │ │ │ └── styles.scss │ │ │ ├── form/ │ │ │ │ ├── BodyModification.tsx │ │ │ │ ├── EditNote.tsx │ │ │ │ ├── Image.tsx │ │ │ │ ├── NavButtons.tsx │ │ │ │ ├── NoteInput.tsx │ │ │ │ ├── SubmitButtons.tsx │ │ │ │ ├── index.ts │ │ │ │ └── styles.scss │ │ │ ├── fragments/ │ │ │ │ ├── ErrorMessage.tsx │ │ │ │ ├── Favorite.tsx │ │ │ │ ├── GenderIcon.tsx │ │ │ │ ├── Help.tsx │ │ │ │ ├── Icon.tsx │ │ │ │ ├── LoadingIndicator.tsx │ │ │ │ ├── PerformerName.tsx │ │ │ │ ├── SearchHint.tsx │ │ │ │ ├── SearchInput.tsx │ │ │ │ ├── SiteLink.tsx │ │ │ │ ├── TagLink.tsx │ │ │ │ ├── Thumbnail.tsx │ │ │ │ ├── Tooltip.tsx │ │ │ │ ├── index.ts │ │ │ │ └── styles.scss │ │ │ ├── image/ │ │ │ │ ├── Image.tsx │ │ │ │ ├── index.ts │ │ │ │ └── styles.scss │ │ │ ├── imageCarousel/ │ │ │ │ ├── ImageCarousel.tsx │ │ │ │ ├── index.ts │ │ │ │ └── styles.scss │ │ │ ├── imageChangeRow/ │ │ │ │ ├── ImageChangeRow.tsx │ │ │ │ ├── index.ts │ │ │ │ └── styles.scss │ │ │ ├── linkedChangeRow/ │ │ │ │ ├── LinkedChangeRow.tsx │ │ │ │ └── index.ts │ │ │ ├── list/ │ │ │ │ ├── EditList.tsx │ │ │ │ ├── List.tsx │ │ │ │ ├── SceneList.tsx │ │ │ │ ├── TagList.tsx │ │ │ │ ├── URLList.tsx │ │ │ │ ├── index.ts │ │ │ │ └── styles.scss │ │ │ ├── listChangeRow/ │ │ │ │ ├── ListChangeRow.tsx │ │ │ │ └── index.ts │ │ │ ├── modal/ │ │ │ │ ├── Modal.tsx │ │ │ │ └── index.ts │ │ │ ├── multiSelect/ │ │ │ │ ├── MultiSelect.tsx │ │ │ │ ├── index.ts │ │ │ │ └── styles.scss │ │ │ ├── pagination/ │ │ │ │ ├── Pagination.tsx │ │ │ │ └── index.ts │ │ │ ├── performerCard/ │ │ │ │ ├── PerformerCard.tsx │ │ │ │ ├── index.ts │ │ │ │ └── styles.scss │ │ │ ├── performerSelect/ │ │ │ │ ├── PerformerSelect.tsx │ │ │ │ ├── index.ts │ │ │ │ └── styles.scss │ │ │ ├── sceneCard/ │ │ │ │ ├── SceneCard.tsx │ │ │ │ ├── index.ts │ │ │ │ └── styles.scss │ │ │ ├── searchField/ │ │ │ │ ├── SearchField.tsx │ │ │ │ ├── handleResult.ts │ │ │ │ ├── index.ts │ │ │ │ └── styles.scss │ │ │ ├── studioSelect/ │ │ │ │ ├── StudioSelect.tsx │ │ │ │ ├── index.ts │ │ │ │ └── styles.scss │ │ │ ├── tagFilter/ │ │ │ │ ├── TagFilter.tsx │ │ │ │ ├── index.ts │ │ │ │ └── styles.scss │ │ │ ├── tagSelect/ │ │ │ │ ├── TagSelect.tsx │ │ │ │ ├── index.ts │ │ │ │ └── styles.scss │ │ │ ├── title/ │ │ │ │ ├── Title.tsx │ │ │ │ └── index.ts │ │ │ ├── urlChangeRow/ │ │ │ │ ├── URLChangeRow.tsx │ │ │ │ └── index.ts │ │ │ └── urlInput/ │ │ │ ├── index.ts │ │ │ ├── styles.scss │ │ │ └── urlInput.tsx │ │ ├── constants/ │ │ │ ├── enums.ts │ │ │ ├── index.ts │ │ │ └── route.ts │ │ ├── context.tsx │ │ ├── graphql/ │ │ │ ├── fragments/ │ │ │ │ ├── CommentFragment.gql │ │ │ │ ├── EditFragment.gql │ │ │ │ ├── FingerprintFragment.gql │ │ │ │ ├── ImageFragment.gql │ │ │ │ ├── PerformerFragment.gql │ │ │ │ ├── QuerySceneFragment.gql │ │ │ │ ├── SceneFragment.gql │ │ │ │ ├── ScenePerformerFragment.gql │ │ │ │ ├── SearchPerformerFragment.gql │ │ │ │ ├── StudioFragment.gql │ │ │ │ ├── TagFragment.gql │ │ │ │ └── URLFragment.gql │ │ │ ├── index.ts │ │ │ ├── mutations/ │ │ │ │ ├── ActivateNewUser.gql │ │ │ │ ├── AddImage.gql │ │ │ │ ├── AddScene.gql │ │ │ │ ├── AddSite.gql │ │ │ │ ├── AddStudio.gql │ │ │ │ ├── AddTagCategory.gql │ │ │ │ ├── AddUser.gql │ │ │ │ ├── AmendEdit.gql │ │ │ │ ├── ApplyEdit.gql │ │ │ │ ├── CancelEdit.gql │ │ │ │ ├── ChangePassword.gql │ │ │ │ ├── ConfirmChangeEmail.gql │ │ │ │ ├── DeleteDraft.gql │ │ │ │ ├── DeleteEdit.gql │ │ │ │ ├── DeleteFingerprintSubmissions.gql │ │ │ │ ├── DeleteScene.gql │ │ │ │ ├── DeleteSite.gql │ │ │ │ ├── DeleteStudio.gql │ │ │ │ ├── DeleteTagCategory.gql │ │ │ │ ├── DeleteUser.gql │ │ │ │ ├── EditComment.gql │ │ │ │ ├── FavoritePerformer.gql │ │ │ │ ├── FavoriteStudio.gql │ │ │ │ ├── GenerateInviteCode.gql │ │ │ │ ├── GrantInvite.gql │ │ │ │ ├── MarkNotificationRead.gql │ │ │ │ ├── MarkNotificationsRead.gql │ │ │ │ ├── MoveFingerprintSubmissions.gql │ │ │ │ ├── NewUser.gql │ │ │ │ ├── PerformerEdit.gql │ │ │ │ ├── PerformerEditUpdate.gql │ │ │ │ ├── RegenerateAPIKey.gql │ │ │ │ ├── RequestChangeEmail.gql │ │ │ │ ├── RescindInviteCode.gql │ │ │ │ ├── ResetPassword.gql │ │ │ │ ├── RevokeInvite.gql │ │ │ │ ├── SceneEdit.gql │ │ │ │ ├── SceneEditUpdate.gql │ │ │ │ ├── StudioEdit.gql │ │ │ │ ├── StudioEditUpdate.gql │ │ │ │ ├── TagEdit.gql │ │ │ │ ├── TagEditUpdate.gql │ │ │ │ ├── UnmatchFingerprint.gql │ │ │ │ ├── UpdateNotificationSubscriptions.gql │ │ │ │ ├── UpdateScene.gql │ │ │ │ ├── UpdateSite.gql │ │ │ │ ├── UpdateStudio.gql │ │ │ │ ├── UpdateTagCategory.gql │ │ │ │ ├── UpdateUser.gql │ │ │ │ ├── ValidateChangeEmail.gql │ │ │ │ ├── Vote.gql │ │ │ │ └── index.ts │ │ │ ├── queries/ │ │ │ │ ├── Categories.gql │ │ │ │ ├── Category.gql │ │ │ │ ├── Config.gql │ │ │ │ ├── Draft.gql │ │ │ │ ├── Drafts.gql │ │ │ │ ├── Edit.gql │ │ │ │ ├── EditUpdate.gql │ │ │ │ ├── Edits.gql │ │ │ │ ├── FullPerformer.gql │ │ │ │ ├── Me.gql │ │ │ │ ├── ModAudits.gql │ │ │ │ ├── PendingEditsCount.gql │ │ │ │ ├── Performer.gql │ │ │ │ ├── Performers.gql │ │ │ │ ├── PublicUser.gql │ │ │ │ ├── QueryExistingPerformer.gql │ │ │ │ ├── QueryExistingScene.gql │ │ │ │ ├── QueryNotifications.gql │ │ │ │ ├── Scene.gql │ │ │ │ ├── ScenePairings.gql │ │ │ │ ├── Scenes.gql │ │ │ │ ├── ScenesWithFingerprints.gql │ │ │ │ ├── ScenesWithoutCount.gql │ │ │ │ ├── SearchAll.gql │ │ │ │ ├── SearchPerformers.gql │ │ │ │ ├── SearchScenes.gql │ │ │ │ ├── SearchTags.gql │ │ │ │ ├── Site.gql │ │ │ │ ├── Sites.gql │ │ │ │ ├── Studio.gql │ │ │ │ ├── StudioPerformers.gql │ │ │ │ ├── Studios.gql │ │ │ │ ├── SubStudios.gql │ │ │ │ ├── Tag.gql │ │ │ │ ├── Tags.gql │ │ │ │ ├── UnreadNotificationCount.gql │ │ │ │ ├── User.gql │ │ │ │ ├── Users.gql │ │ │ │ ├── Version.gql │ │ │ │ └── index.ts │ │ │ ├── scalars.d.ts │ │ │ └── types.ts │ │ ├── hooks/ │ │ │ ├── index.ts │ │ │ ├── toast.scss │ │ │ ├── useAuth.tsx │ │ │ ├── useBeforeUnload.ts │ │ │ ├── useCurrentUser.tsx │ │ │ ├── useEditFilter.tsx │ │ │ ├── usePagination.ts │ │ │ ├── useQueryParams.ts │ │ │ └── useToast.tsx │ │ ├── index.tsx │ │ ├── modules.d.ts │ │ ├── pages/ │ │ │ ├── activateUser/ │ │ │ │ ├── ActivateUser.tsx │ │ │ │ └── index.ts │ │ │ ├── audits/ │ │ │ │ ├── AmendmentAuditDetails.tsx │ │ │ │ ├── AuditRow.tsx │ │ │ │ ├── Audits.tsx │ │ │ │ ├── DeleteAuditDetails.tsx │ │ │ │ └── index.tsx │ │ │ ├── categories/ │ │ │ │ ├── Categories.tsx │ │ │ │ ├── Category.tsx │ │ │ │ ├── CategoryAdd.tsx │ │ │ │ ├── CategoryEdit.tsx │ │ │ │ ├── categoryForm/ │ │ │ │ │ ├── CategoryForm.tsx │ │ │ │ │ └── index.ts │ │ │ │ └── index.tsx │ │ │ ├── drafts/ │ │ │ │ ├── Draft.tsx │ │ │ │ ├── Drafts.tsx │ │ │ │ ├── PerformerDraft.tsx │ │ │ │ ├── SceneDraft.tsx │ │ │ │ ├── index.tsx │ │ │ │ └── parse.ts │ │ │ ├── edits/ │ │ │ │ ├── Edit.tsx │ │ │ │ ├── EditAmend.tsx │ │ │ │ ├── EditAmendForm.tsx │ │ │ │ ├── EditUpdate.tsx │ │ │ │ ├── Edits.tsx │ │ │ │ ├── components/ │ │ │ │ │ ├── DeleteEditModal.tsx │ │ │ │ │ └── UpdateCount.tsx │ │ │ │ └── index.tsx │ │ │ ├── forgotPassword/ │ │ │ │ ├── ForgotPassword.tsx │ │ │ │ └── index.ts │ │ │ ├── home/ │ │ │ │ ├── Home.tsx │ │ │ │ ├── index.ts │ │ │ │ └── styles.scss │ │ │ ├── index.tsx │ │ │ ├── notifications/ │ │ │ │ ├── CommentNotification.tsx │ │ │ │ ├── EditNotification.tsx │ │ │ │ ├── Notification.tsx │ │ │ │ ├── Notifications.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── sceneNotification.tsx │ │ │ │ ├── styles.scss │ │ │ │ └── types.ts │ │ │ ├── performers/ │ │ │ │ ├── Performer.tsx │ │ │ │ ├── PerformerAdd.tsx │ │ │ │ ├── PerformerDelete.tsx │ │ │ │ ├── PerformerEdit.tsx │ │ │ │ ├── PerformerEditUpdate.tsx │ │ │ │ ├── PerformerMerge.tsx │ │ │ │ ├── Performers.tsx │ │ │ │ ├── components/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── performerInfo.tsx │ │ │ │ │ └── scenePairings.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── performerForm/ │ │ │ │ │ ├── ExistingPerformerAlert.tsx │ │ │ │ │ ├── PerformerForm.tsx │ │ │ │ │ ├── diff.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── schema.ts │ │ │ │ │ └── types.ts │ │ │ │ └── styles.scss │ │ │ ├── registerUser/ │ │ │ │ ├── Register.tsx │ │ │ │ └── index.ts │ │ │ ├── resetPassword/ │ │ │ │ ├── ResetPassword.tsx │ │ │ │ └── index.ts │ │ │ ├── scenes/ │ │ │ │ ├── Scene.tsx │ │ │ │ ├── SceneAdd.tsx │ │ │ │ ├── SceneDelete.tsx │ │ │ │ ├── SceneEdit.tsx │ │ │ │ ├── SceneEditUpdate.tsx │ │ │ │ ├── Scenes.tsx │ │ │ │ ├── components/ │ │ │ │ │ └── fingerprints/ │ │ │ │ │ ├── DeleteFingerprintsModal.tsx │ │ │ │ │ ├── FingerprintTable.tsx │ │ │ │ │ ├── FingerprintTableHeader.tsx │ │ │ │ │ ├── FingerprintTableRow.tsx │ │ │ │ │ ├── MoveFingerprintsModal.tsx │ │ │ │ │ ├── types.ts │ │ │ │ │ ├── useFingerprintOperations.ts │ │ │ │ │ ├── useFingerprintSelection.ts │ │ │ │ │ └── useFingerprintSort.ts │ │ │ │ ├── index.tsx │ │ │ │ ├── sceneForm/ │ │ │ │ │ ├── ExistingSceneAlert.tsx │ │ │ │ │ ├── SceneForm.tsx │ │ │ │ │ ├── diff.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── schema.ts │ │ │ │ │ ├── styles.scss │ │ │ │ │ └── types.ts │ │ │ │ └── styles.scss │ │ │ ├── search/ │ │ │ │ ├── GenderFacet.tsx │ │ │ │ ├── PerformerCard.tsx │ │ │ │ ├── SceneCard.tsx │ │ │ │ ├── SearchAll.tsx │ │ │ │ ├── SearchLayout.tsx │ │ │ │ ├── SearchPerformersTab.tsx │ │ │ │ ├── SearchScenesTab.tsx │ │ │ │ ├── index.tsx │ │ │ │ └── search.scss │ │ │ ├── sites/ │ │ │ │ ├── Site.tsx │ │ │ │ ├── SiteAdd.tsx │ │ │ │ ├── SiteEdit.tsx │ │ │ │ ├── Sites.tsx │ │ │ │ ├── index.tsx │ │ │ │ └── siteForm/ │ │ │ │ ├── SiteForm.tsx │ │ │ │ └── index.ts │ │ │ ├── studios/ │ │ │ │ ├── Studio.tsx │ │ │ │ ├── StudioAdd.tsx │ │ │ │ ├── StudioDelete.tsx │ │ │ │ ├── StudioEdit.tsx │ │ │ │ ├── StudioEditUpdate.tsx │ │ │ │ ├── Studios.tsx │ │ │ │ ├── components/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── studioPerformers.tsx │ │ │ │ │ ├── subStudioList.tsx │ │ │ │ │ └── subStudioPreview.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── studioForm/ │ │ │ │ │ ├── StudioForm.tsx │ │ │ │ │ ├── diff.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── schema.ts │ │ │ │ │ └── types.ts │ │ │ │ └── styles.scss │ │ │ ├── tags/ │ │ │ │ ├── Tag.tsx │ │ │ │ ├── TagAdd.tsx │ │ │ │ ├── TagDelete.tsx │ │ │ │ ├── TagEdit.tsx │ │ │ │ ├── TagEditUpdate.tsx │ │ │ │ ├── TagMerge.tsx │ │ │ │ ├── Tags.tsx │ │ │ │ ├── index.tsx │ │ │ │ └── tagForm/ │ │ │ │ ├── TagForm.tsx │ │ │ │ ├── diff.ts │ │ │ │ ├── index.ts │ │ │ │ ├── schema.ts │ │ │ │ └── types.ts │ │ │ ├── users/ │ │ │ │ ├── GenerateInviteKeyModal.tsx │ │ │ │ ├── User.tsx │ │ │ │ ├── UserAdd.tsx │ │ │ │ ├── UserConfirmChangeEmail.tsx │ │ │ │ ├── UserEdit.tsx │ │ │ │ ├── UserEditForm.tsx │ │ │ │ ├── UserEdits.tsx │ │ │ │ ├── UserFingerprints.tsx │ │ │ │ ├── UserFingerprintsList/ │ │ │ │ │ ├── UserFingerprint.tsx │ │ │ │ │ ├── UserFingerprintsList.tsx │ │ │ │ │ ├── UserSceneLine.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── UserForm.tsx │ │ │ │ ├── UserNotificationPreferences.tsx │ │ │ │ ├── UserPassword.tsx │ │ │ │ ├── UserPasswordForm.tsx │ │ │ │ ├── UserValidateChangeEmail.tsx │ │ │ │ ├── Users.tsx │ │ │ │ ├── index.tsx │ │ │ │ └── styles.scss │ │ │ └── version/ │ │ │ ├── Version.tsx │ │ │ └── index.ts │ │ ├── styles/ │ │ │ └── theme.scss │ │ └── utils/ │ │ ├── country.ts │ │ ├── createClient.ts │ │ ├── data.ts │ │ ├── date.ts │ │ ├── diff.ts │ │ ├── edit.ts │ │ ├── enum.ts │ │ ├── general.ts │ │ ├── index.ts │ │ ├── intl.ts │ │ ├── markdown.tsx │ │ ├── route.ts │ │ ├── transforms.ts │ │ ├── url.ts │ │ └── user.ts │ ├── tsconfig.json │ └── vite.config.mjs ├── go.mod ├── go.sum ├── gqlgen.yml ├── graphql/ │ └── schema/ │ ├── schema.graphql │ └── types/ │ ├── config.graphql │ ├── draft.graphql │ ├── edit.graphql │ ├── filter.graphql │ ├── image.graphql │ ├── misc.graphql │ ├── mod_audit.graphql │ ├── notifications.graphql │ ├── performer.graphql │ ├── scene.graphql │ ├── site.graphql │ ├── studio.graphql │ ├── tag.graphql │ ├── user.graphql │ └── version.graphql ├── internal/ │ ├── api/ │ │ ├── context_keys.go │ │ ├── directives.go │ │ ├── draft_integration_test.go │ │ ├── edit_amend_integration_test.go │ │ ├── edit_delete_integration_test.go │ │ ├── edit_integration_test.go │ │ ├── field_test.go │ │ ├── fingerprint_filter.go │ │ ├── graphql_client_test.go │ │ ├── integration_test.go │ │ ├── loaders.go │ │ ├── notification_integration_test.go │ │ ├── performer_edit_integration_test.go │ │ ├── performer_integration_test.go │ │ ├── performer_resolver_integration_test.go │ │ ├── resolver.go │ │ ├── resolver_model_draft.go │ │ ├── resolver_model_edit.go │ │ ├── resolver_model_edit_comment.go │ │ ├── resolver_model_edit_vote.go │ │ ├── resolver_model_image.go │ │ ├── resolver_model_notification.go │ │ ├── resolver_model_performer.go │ │ ├── resolver_model_performer_draft.go │ │ ├── resolver_model_performer_edit.go │ │ ├── resolver_model_scene.go │ │ ├── resolver_model_scene_draft.go │ │ ├── resolver_model_scene_edit.go │ │ ├── resolver_model_site.go │ │ ├── resolver_model_studio.go │ │ ├── resolver_model_studio_edit.go │ │ ├── resolver_model_tag.go │ │ ├── resolver_model_tag_category.go │ │ ├── resolver_model_tag_edit.go │ │ ├── resolver_model_url.go │ │ ├── resolver_model_user.go │ │ ├── resolver_mutation_draft.go │ │ ├── resolver_mutation_edit.go │ │ ├── resolver_mutation_image.go │ │ ├── resolver_mutation_notifications.go │ │ ├── resolver_mutation_performer.go │ │ ├── resolver_mutation_scene.go │ │ ├── resolver_mutation_site.go │ │ ├── resolver_mutation_studio.go │ │ ├── resolver_mutation_tag.go │ │ ├── resolver_mutation_tag_category.go │ │ ├── resolver_mutation_user.go │ │ ├── resolver_query_draft.go │ │ ├── resolver_query_edit.go │ │ ├── resolver_query_mod_audit.go │ │ ├── resolver_query_notifications.go │ │ ├── resolver_query_performer.go │ │ ├── resolver_query_scene.go │ │ ├── resolver_query_site.go │ │ ├── resolver_query_studio.go │ │ ├── resolver_query_tag.go │ │ ├── resolver_query_tag_category.go │ │ ├── resolver_query_user.go │ │ ├── routes_image.go │ │ ├── routes_root.go │ │ ├── scene_edit_integration_test.go │ │ ├── scene_integration_test.go │ │ ├── search_integration_test.go │ │ ├── server.go │ │ ├── session.go │ │ ├── site_integration_test.go │ │ ├── studio_edit_integration_test.go │ │ ├── studio_integration_test.go │ │ ├── tag_category_integration_test.go │ │ ├── tag_edit_integration_test.go │ │ ├── tag_integration_test.go │ │ ├── user_integration_test.go │ │ └── utils.go │ ├── auth/ │ │ └── authorization.go │ ├── autocert/ │ │ └── autocert.go │ ├── config/ │ │ ├── config.go │ │ └── paths.go │ ├── converter/ │ │ ├── converter.go │ │ └── gen/ │ │ ├── extensions.go │ │ ├── generated.go │ │ └── interfaces.go │ ├── cron/ │ │ └── cron.go │ ├── database/ │ │ ├── database.go │ │ ├── migrations/ │ │ │ └── postgres/ │ │ │ ├── 01_initial.down.sql │ │ │ ├── 01_initial.up.sql │ │ │ ├── 02_create_search.down.sql │ │ │ ├── 02_create_search.up.sql │ │ │ ├── 03_misc.up.sql │ │ │ ├── 04_image_tables.up.sql │ │ │ ├── 05_edits.up.sql │ │ │ ├── 06_deletion_and_redirects.up.sql │ │ │ ├── 07_optimization_indexes.up.sql │ │ │ ├── 08_user_invite.up.sql │ │ │ ├── 09_image_data.up.sql │ │ │ ├── 10_tag_categories.up.sql │ │ │ ├── 11_image_constraints.up.sql │ │ │ ├── 12_fix_performer_trigger.up.sql │ │ │ ├── 13_sort_indexes.up.sql │ │ │ ├── 14_phash_distance_search.up.sql │ │ │ ├── 15_scene_fingerprint_submissions.up.sql │ │ │ ├── 16_fix_scene_update_trigger.up.sql │ │ │ ├── 17_edit_votes.up.sql │ │ │ ├── 18_fingerprint_user.up.sql │ │ │ ├── 19_scene_created_index.up.sql │ │ │ ├── 20_edit_constraints.up.sql │ │ │ ├── 21_site_urls.up.sql │ │ │ ├── 22_performer_search_indexes.up.sql │ │ │ ├── 23_favorites.up.sql │ │ │ ├── 24_drafts.up.sql │ │ │ ├── 25_scene_codes.up.sql │ │ │ ├── 26_scene_partial_date.down.sql │ │ │ ├── 26_scene_partial_date.up.sql │ │ │ ├── 27_edit_closed_at.up.sql │ │ │ ├── 28_studio_favorite_index.up.sql │ │ │ ├── 29_scene_edit_fingerprint_index.up.sql │ │ │ ├── 30_edit_bot.up.sql │ │ │ ├── 31_scenes_deleted_idx.up.sql │ │ │ ├── 32_edit_indexes.up.sql │ │ │ ├── 33_invite_key_uses.up.sql │ │ │ ├── 34_fingerprints.up.sql │ │ │ ├── 35_websearch.up.sql │ │ │ ├── 36_drop_unique_invite.up.sql │ │ │ ├── 37_tokens.up.sql │ │ │ ├── 38_scenes_studio_id_index.up.sql │ │ │ ├── 39_edits_updates.up.sql │ │ │ ├── 40_fingerprint_vote.up.sql │ │ │ ├── 41_notifications.up.sql │ │ │ ├── 42_date_columns.up.sql │ │ │ ├── 43_studio_aliases.up.sql │ │ │ ├── 44_performer_death_date.up.sql │ │ │ ├── 45_scene_production_date.up.sql │ │ │ ├── 46_update_default_notifications.up.sql │ │ │ ├── 47_favorite_unique.up.sql │ │ │ ├── 48_fingerprinted_scene_edit_notification.up.sql │ │ │ ├── 49_entity_search_lower_idx.up.sql │ │ │ ├── 50_rename_url_siteid.up.sql │ │ │ ├── 51_scene_deleted_sort_indexes.up.sql │ │ │ ├── 52_fingerprint_hash_bigint.up.sql │ │ │ ├── 53_varchar_to_text.up.sql │ │ │ ├── 54_delete_soft_deleted_aliases.up.sql │ │ │ ├── 55_fix_edit_data_dates.up.sql │ │ │ ├── 56_paradedb_search.up.sql │ │ │ └── 57_mod_audit.up.sql │ │ └── testutil/ │ │ └── testutil.go │ ├── dataloader/ │ │ ├── bodymodificationsloader_gen.go │ │ ├── boolsloader_gen.go │ │ ├── editcommentloader_gen.go │ │ ├── editloader_gen.go │ │ ├── fingerprintsloader_gen.go │ │ ├── imageloader_gen.go │ │ ├── loaders.go │ │ ├── performerloader_gen.go │ │ ├── sceneappearancesloader_gen.go │ │ ├── sceneloader_gen.go │ │ ├── siteloader_gen.go │ │ ├── stringsloader_gen.go │ │ ├── studioloader_gen.go │ │ ├── submittedfingerprintsloader_gen.go │ │ ├── tagcategoryloader_gen.go │ │ ├── tagloader_gen.go │ │ ├── urlloader_gen.go │ │ └── uuidsloader_gen.go │ ├── email/ │ │ ├── manager.go │ │ ├── templates/ │ │ │ ├── email.html │ │ │ └── email.txt │ │ └── user.go │ ├── image/ │ │ ├── cache/ │ │ │ └── cache.go │ │ ├── resize_unix.go │ │ ├── resize_windows.go │ │ └── sort.go │ ├── models/ │ │ ├── assign/ │ │ │ └── assign.go │ │ ├── extension_criterion_input.go │ │ ├── extension_edit_details.go │ │ ├── extension_edit_details_test.go │ │ ├── extension_role_enum.go │ │ ├── generate.go │ │ ├── generated_exec.go │ │ ├── generated_models.go │ │ ├── model_draft.go │ │ ├── model_edit.go │ │ ├── model_image.go │ │ ├── model_invite_key.go │ │ ├── model_mod_audit.go │ │ ├── model_notification.go │ │ ├── model_performer.go │ │ ├── model_scene.go │ │ ├── model_site.go │ │ ├── model_studio.go │ │ ├── model_tag.go │ │ ├── model_tag_category.go │ │ ├── model_user.go │ │ ├── model_user_tokens.go │ │ ├── scalars.go │ │ ├── translate.go │ │ ├── url.go │ │ └── validator/ │ │ └── validator.go │ ├── queries/ │ │ ├── copyfrom.go │ │ ├── db.go │ │ ├── draft.sql.go │ │ ├── edit.sql.go │ │ ├── fingerprint.sql.go │ │ ├── helpers.go │ │ ├── image.sql.go │ │ ├── invite_key.sql.go │ │ ├── mod_audit.sql.go │ │ ├── models.go │ │ ├── notification.sql.go │ │ ├── performer.sql.go │ │ ├── querier.go │ │ ├── scene.sql.go │ │ ├── site.sql.go │ │ ├── sql/ │ │ │ ├── draft.sql │ │ │ ├── edit.sql │ │ │ ├── fingerprint.sql │ │ │ ├── image.sql │ │ │ ├── invite_key.sql │ │ │ ├── mod_audit.sql │ │ │ ├── notification.sql │ │ │ ├── performer.sql │ │ │ ├── scene.sql │ │ │ ├── site.sql │ │ │ ├── studio.sql │ │ │ ├── tag.sql │ │ │ ├── tag_category.sql │ │ │ ├── user.sql │ │ │ └── user_token.sql │ │ ├── studio.sql.go │ │ ├── tag.sql.go │ │ ├── tag_category.sql.go │ │ ├── types.go │ │ ├── user.sql.go │ │ └── user_token.sql.go │ ├── service/ │ │ ├── draft/ │ │ │ └── service.go │ │ ├── edit/ │ │ │ ├── edit.go │ │ │ ├── modbot.go │ │ │ ├── performer.go │ │ │ ├── query.go │ │ │ ├── scene.go │ │ │ ├── service.go │ │ │ ├── studio.go │ │ │ ├── tag.go │ │ │ └── validate.go │ │ ├── errutil/ │ │ │ └── errors.go │ │ ├── factory.go │ │ ├── image/ │ │ │ ├── service.go │ │ │ └── utils.go │ │ ├── interface.go │ │ ├── invite/ │ │ │ └── service.go │ │ ├── mod_audit/ │ │ │ └── mod_audit.go │ │ ├── notification/ │ │ │ └── service.go │ │ ├── performer/ │ │ │ ├── joins.go │ │ │ ├── query.go │ │ │ └── service.go │ │ ├── query/ │ │ │ ├── criterion.go │ │ │ └── helpers.go │ │ ├── scene/ │ │ │ ├── query.go │ │ │ └── service.go │ │ ├── site/ │ │ │ ├── query.go │ │ │ └── service.go │ │ ├── studio/ │ │ │ ├── query.go │ │ │ └── service.go │ │ ├── tag/ │ │ │ ├── query.go │ │ │ └── service.go │ │ ├── user/ │ │ │ ├── activation.go │ │ │ ├── apikey.go │ │ │ ├── invite.go │ │ │ ├── joins.go │ │ │ ├── password.go │ │ │ ├── query.go │ │ │ ├── service.go │ │ │ ├── token.go │ │ │ ├── user.go │ │ │ └── validate.go │ │ └── usertoken/ │ │ └── service.go │ └── storage/ │ ├── favicon.go │ ├── file.go │ ├── image_backend.go │ └── s3.go ├── pkg/ │ ├── logger/ │ │ ├── logger.go │ │ ├── otel.go │ │ └── progress_formatter.go │ └── utils/ │ ├── arguments.go │ ├── crypto.go │ ├── date.go │ ├── enum.go │ ├── file.go │ ├── json.go │ ├── password_blacklist.go │ ├── slice_compare.go │ └── slice_compare_test.go ├── scripts/ │ └── getDate.go └── sqlc.yaml ================================================ FILE CONTENTS ================================================ ================================================ FILE: .dockerignore ================================================ # Binaries for programs and plugins *.exe *.exe~ *.dll *.so *.dylib # Test binary, built with `go test -c` *.test # Output of the go coverage tool, specifically when used with LiteIDE *.out #### # Visual Studio Code #### .vscode #### # Jetbrains #### # User-specific stuff .idea/**/workspace.xml .idea/**/tasks.xml .idea/**/usage.statistics.xml .idea/**/dictionaries .idea/**/shelf # Generated files .idea/**/contentModel.xml # Sensitive or high-churn files .idea/**/dataSources/ .idea/**/dataSources.ids .idea/**/dataSources.local.xml .idea/**/sqlDataSources.xml .idea/**/dynamic.xml .idea/**/uiDesigner.xml .idea/**/dbnavigator.xml # Vim *.swp #### # Random #### frontend/node_modules/* frontend/build/* *.db stashdb stash-box dist pkg/models/generated_*.go # TODO - we'll add this in later vendor docker ================================================ FILE: .gitattributes ================================================ go.mod text eol=lf go.sum text eol=lf ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: Bug report about: Create a report to help us improve title: "[Bug Report] Short Form Subject (50 Chars or less)" labels: help wanted assignees: '' --- **Describe the bug** A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' 4. See error **Expected behavior** A clear and concise description of what you expected to happen. **Screenshots** If applicable, add screenshots to help explain your problem please ensure that your screenshots are SFW or at least appropriately censored. **Desktop (please complete the following information):** - OS: [e.g. iOS] - Browser [e.g. chrome, safari] - Version [e.g. 22] **Smartphone (please complete the following information):** - Device: [e.g. iPhone6] - OS: [e.g. iOS8.1] - Browser [e.g. stock browser, safari] - Version [e.g. 22] **Additional context** Add any other context about the problem here. ================================================ FILE: .github/ISSUE_TEMPLATE/discussion---request-for-commentary--rfc-.md ================================================ --- name: Discussion / Request for Commentary [RFC] about: This is for issues that will be discussed and won't necessarily result directly in commits or pull requests. title: "[RFC] Short Form Title" labels: help wanted assignees: '' --- ## Long Form ## Examples ## Reference Reading ================================================ FILE: .github/ISSUE_TEMPLATE/feature_request.md ================================================ --- name: Feature request about: Suggest an idea for this project title: "[Feature] Short Form Title (50 chars or less.)" labels: enhancement assignees: '' --- **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] **Describe the solution you'd like** A clear and concise description of what you want to happen. **Describe alternatives you've considered** A clear and concise description of any alternative solutions or features you've considered. **Additional context** Add any other context or screenshots about the feature request here. ================================================ FILE: .github/workflows/build.yml ================================================ name: Build on: push: branches: [ master ] pull_request: branches: [ master ] release: types: [ published ] concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: build: runs-on: ubuntu-24.04 steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Build custom PostgreSQL image run: docker build -t stash-box-postgres -f docker/production/postgres/Dockerfile docker/production/postgres - name: Start PostgreSQL container run: | docker run -d \ --name postgres \ -e POSTGRES_DB=postgres \ -e POSTGRES_PASSWORD=postgres \ -e POSTGRES_USER=postgres \ -p 5432:5432 \ --health-cmd pg_isready \ --health-interval 10s \ --health-timeout 5s \ --health-retries 5 \ stash-box-postgres - name: Wait for PostgreSQL to be ready run: | until docker exec postgres pg_isready; do echo "Waiting for postgres..." sleep 2 done - name: Install vips run: sudo apt-get update && sudo apt-get install -y libvips-dev - name: Install Go uses: actions/setup-go@v5 with: go-version: 1.25.x - name: Install Node uses: actions/setup-node@v4 with: node-version: '24' - name: Install PNPM uses: pnpm/action-setup@v4 with: version: 9 - name: Install sqlc uses: sqlc-dev/setup-sqlc@v4 with: sqlc-version: '1.29.0' - name: Cache node modules uses: actions/cache@v4 env: cache-name: cache-node_modules with: path: frontend/node_modules key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('frontend/pnpm-lock.yaml') }} - name: Cache UI build uses: actions/cache@v4 id: cache-ui env: cache-name: cache-ui with: path: frontend/build key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('frontend/pnpm-lock.yaml', 'frontend/vite.config.js', 'frontend/src/**', 'graphql/**/*.graphql') }} - name: Cache go build uses: actions/cache@v4 env: cache-name: cache-go-cache-2 with: path: | ~/go/pkg/mod .go-cache key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('go.mod', '**/go.sum') }} - name: Pre-install run: make pre-ui - name: Generate run: make generate - name: Check generated files run: | if ! git diff --exit-code; then echo "::error::Generated files have changed. Run 'make generate' locally and commit the changes." git diff exit 1 fi - name: Build UI # skip UI build for pull requests if UI is unchanged (UI was cached) # this means that the build version/time may be incorrect if the UI is # not changed in a pull request if: ${{ github.event_name != 'pull_request' || steps.cache-ui.outputs.cache-hit != 'true' }} run: make ui - name: Run tests env: POSTGRES_DB: postgres:postgres@localhost/postgres?sslmode=disable run: make it - name: Set PR version if: ${{ github.event_name == 'pull_request' && github.base_ref != 'refs/heads/master'}} run: echo "BUILD_TYPE=PR" >> $GITHUB_ENV - name: Set Official version if: ${{ github.event_name == 'release' && github.ref != 'refs/tags/latest-develop' }} run: echo "BUILD_TYPE=OFFICIAL" >> $GITHUB_ENV - name: Set Development version if: ${{ github.event_name == 'push' }} run: echo "BUILD_TYPE=DEVELOPMENT" >> $GITHUB_ENV - name: Crosscompile binaries run: make cross-compile env: BUILD_TYPE: "${{ env.BUILD_TYPE }}" - name: Generate checksums run: | git describe --tags --exclude latest-develop | tee CHECKSUMS_SHA1 sha1sum dist/stash-box-* | sed 's/dist\/.*\///g' | tee -a CHECKSUMS_SHA1 echo "STASH_BOX_VERSION=$(git describe --tags --exclude latest-develop)" >> $GITHUB_ENV - name: Upload Windows binary # only upload binaries for pull requests if: ${{ github.event_name == 'pull_request' && github.base_ref != 'refs/heads/master'}} uses: actions/upload-artifact@v4 with: name: stash-box-win.exe path: dist/stash-box-windows.exe - name: Upload Linux binary # only upload binaries for pull requests if: ${{ github.event_name == 'pull_request' && github.base_ref != 'refs/heads/master'}} uses: actions/upload-artifact@v4 with: name: stash-box-linux path: dist/stash-box-linux - name: Update latest-develop tag if: ${{ github.event_name == 'push' }} run : git tag -f latest-develop; git push -f --tags - name: Development Release if: ${{ github.event_name == 'push' }} uses: marvinpinto/action-automatic-releases@v1.1.2 with: repo_token: "${{ secrets.GITHUB_TOKEN }}" prerelease: true automatic_release_tag: latest-develop title: "${{ env.STASH_BOX_VERSION }}: Latest development build" files: | dist/stash-box-windows.exe dist/stash-box-linux CHECKSUMS_SHA1 - name: Master release if: ${{ github.event_name == 'release' && github.ref != 'refs/tags/latest-develop' }} uses: WithoutPants/github-release@v2.0.4 with: token: "${{ secrets.GITHUB_TOKEN }}" allow_override: true files: | dist/stash-box-windows.exe dist/stash-box-linux CHECKSUMS_SHA1 gzip: false - name: Login to DockerHub if: ${{ github.event_name != 'pull_request' }} uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Development Docker if: ${{ github.event_name == 'push' }} run: | docker build -t stashapp/stash-box:development -f ./docker/ci/x86_64/Dockerfile ./dist docker push stashapp/stash-box:development - name: Release Docker if: ${{ github.event_name == 'release' && github.ref != 'refs/tags/latest-develop' }} run: | docker build -t stashapp/stash-box:latest -f ./docker/ci/x86_64/Dockerfile ./dist docker push stashapp/stash-box:latest ================================================ FILE: .github/workflows/frontend-lint.yml ================================================ name: Lint (frontend) on: push: pull_request: concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: build: runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 - name: Install Node uses: actions/setup-node@v4 with: node-version: '24' - name: Install PNPM uses: pnpm/action-setup@v4 with: version: 9 - name: Cache node packages uses: actions/cache@v4 env: cache-name: cache-node_modules with: path: frontend/node_modules key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('frontend/pnpm-lock.yaml') }} - name: Install node packages run: make pre-ui - name: Validate UI run: make ui-validate ================================================ FILE: .github/workflows/golangci-lint.yml ================================================ name: Lint (golangci-lint) on: push: pull_request: jobs: golangci: name: lint runs-on: ubuntu-24.04 steps: - name: Install vips run: sudo apt-get update && sudo apt-get install -y libvips-dev - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version: 1.25.x - run: mkdir frontend/build && touch frontend/build/dummy - name: Run golangci-lint uses: golangci/golangci-lint-action@v8 with: # Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version version: latest ================================================ FILE: .gitignore ================================================ # Binaries for programs and plugins *.exe *.exe~ *.dll *.so *.dylib # Test binary, built with `go test -c` *.test # Output of the go coverage tool, specifically when used with LiteIDE *.out #### # Visual Studio Code #### .vscode #### # Jetbrains #### # User-specific stuff .idea/**/workspace.xml .idea/**/tasks.xml .idea/**/usage.statistics.xml .idea/**/dictionaries .idea/**/shelf # Generated files .idea/**/contentModel.xml # Sensitive or high-churn files .idea/**/dataSources/ .idea/**/dataSources.ids .idea/**/dataSources.local.xml .idea/**/sqlDataSources.xml .idea/**/dynamic.xml .idea/**/uiDesigner.xml .idea/**/dbnavigator.xml # Vim *.swp # macOS .DS_Store #### # Random #### node_modules *.db .go-cache/ stashdb /stash-box dist stash-box-config.yml # TODO - we'll add this in later vendor ================================================ FILE: .golangci.yml ================================================ version: "2" run: go: "1.25" linters: enable: - copyloopvar - dogsled - errorlint - exhaustive - gocritic - misspell - noctx - revive - rowserrcheck - sqlclosecheck settings: exhaustive: default-signifies-exhaustive: true revive: confidence: 0.8 severity: error rules: - name: blank-imports disabled: true - name: context-as-argument - name: context-keys-type - name: dot-imports - name: error-return - name: error-strings - name: error-naming - name: exported - name: if-return disabled: false - name: increment-decrement - name: var-naming arguments: - - IDS - [] - - skip-package-name-checks: true - name: var-declaration - name: package-comments - name: range - name: receiver-naming - name: time-naming - name: unexported-return disabled: true - name: indent-error-flow - name: errorf - name: empty-block - name: superfluous-else - name: unused-parameter disabled: true - name: unreachable-code - name: redefines-builtin-id exclusions: generated: lax presets: - comments - common-false-positives - legacy - std-error-handling paths: - third_party$ - builtin$ - examples$ formatters: enable: - gofmt exclusions: generated: lax paths: - third_party$ - builtin$ - examples$ ================================================ FILE: CLAUDE.md ================================================ # CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview Stash-box is an open-source video indexing and metadata API server for adult content, developed by Stash App. It serves as a community-driven database of metadata, similar to MusicBrainz for music. The application uses Go for the backend API with GraphQL, and React/TypeScript for the frontend. ## Development Commands ### Backend Development - `make build` - Build the Go binary with embedded frontend - `make test` - Run unit tests - `make it` - Run integration tests - `make lint` - Run golangci-lint on Go code - `make fmt` - Format Go code with gofmt - `make generate` - Regenerate GraphQL files, sqlc queries, and UI types - `make generate-backend` - Generate Go GraphQL files only - `make generate-ui` - Generate frontend GraphQL types only - `make generate-sqlc` - Generate sqlc query code only - `make generate-goverter` - Generate goverter type conversion code - `make generate-dataloaders` - Generate dataloader files ### Frontend Development - `make pre-ui` - Install frontend dependencies via pnpm - `make ui` - Build the frontend for production - `make ui-start` - Start frontend development server - `make ui-fmt` - Format frontend code with prettier - `make ui-validate` - Run linting, format checking, and TypeScript validation ### Complete Build Process - `make stash-box` - Full build: dependencies, generation, UI, linting, and binary ### Database Setup The application requires PostgreSQL with specific extensions: - Run `CREATE EXTENSION pg_trgm; CREATE EXTENSION pgcrypto;` as superuser before first run - Database schema migrations run automatically on startup - **Migrations**: Located in `internal/database/migrations/postgres/` and executed sequentially by filename - Default connection string: `postgres@localhost/stash-box?sslmode=disable` - **Query Code Generation**: Uses sqlc (configured in `sqlc.yaml`) to generate type-safe Go code from SQL queries ## Architecture ### Backend (`internal/` directory) - **`internal/api/`** - GraphQL resolvers, HTTP handlers, and server setup - **`internal/auth/`** - Authentication and authorization logic - **`internal/models/`** - Data models, database entity definitions, and generated GraphQL types - **`internal/database/`** - Database connection, migrations, and PostgreSQL-specific code - **`internal/queries/`** - Type-safe database query code generated by sqlc from SQL files - **`internal/service/`** - Business logic layer organized by entity (draft, edit, image, performer, scene, site, studio, tag, user, etc.) - **`internal/email/`** - Email handling and templates - **`internal/image/`** - Image processing, storage (local/S3), caching, and resizing - **`internal/storage/`** - Storage abstraction layer for local/S3 backends - **`internal/config/`** - Configuration management and parsing - **`internal/converter/`** - Generated type conversion code via goverter - **`internal/dataloader/`** - Generated DataLoader implementations for efficient GraphQL N+1 query resolution - **`internal/cron/`** - Scheduled task management ### Frontend (`frontend/` directory) - **`frontend/src/pages/`** - Page components organized by entity type (performers, scenes, studios, tags, users) - **`frontend/src/components/`** - Reusable UI components and form elements - **`frontend/src/graphql/`** - GraphQL queries, mutations, fragments, and generated TypeScript types - **`frontend/src/hooks/`** - Custom React hooks for authentication, pagination, and state management - **`frontend/src/utils/`** - Utility functions for data transformation, routing, and validation ### Key Concepts - **Entities**: Performers, Scenes, Studios, Tags, Sites - the main data types in the system - **Edits**: All changes go through an edit/voting system before being applied to entities - **Drafts**: Temporary submissions that can be converted to edits - **Roles**: User permission system (READ, VOTE, EDIT, MODIFY, ADMIN) controlling access to operations - **Images**: Stored locally or on S3, with automatic resizing and caching capabilities - **Fingerprints**: Used for scene matching and duplicate detection via three algorithms: - **MD5**: Hash of entire video file for exact matching - **OSHASH**: OpenSubtitles Hash implementation - hash of leading and trailing 64kb of video file - **PHASH**: Perceptual hash based on a 5x5 grid of frames at regular intervals for content-based matching ### GraphQL Schema - Schema files in `graphql/schema/` define the API structure - Code generation via gqlgen creates Go resolvers and TypeScript types - Uses dataloader pattern to prevent N+1 queries when fetching related data - **Authorization Directives**: `@hasRole(role: ROLE)` implemented in `internal/api/directives.go` for field-level access control ### Configuration - YAML configuration file (`stash-box-config.yml`) controls server behavior - Support for PostgreSQL connection settings, image storage, email, and security options - Environment variables can override configuration values ## Testing ### Backend Tests - **Integration tests preferred**: All tests should be integration tests utilizing the GraphQL API as much as possible - Unit tests: `make test` - Fast tests that don't require database (use sparingly) - Integration tests: `make it` - Full tests against PostgreSQL test database - Integration tests use PostgreSQL with default connection string `postgres@localhost/stash-box-test?sslmode=disable` - Can override test database via `POSTGRES_DB` environment variable - **Warning**: Integration tests drop all tables, never run against production database - Test files follow pattern `internal/api/*_integration_test.go` with GraphQL client helper in `graphql_client_test.go` - **Test Data Setup**: Tests use the service layer to create test data (see `internal/api/integration_test.go` for user setup example) ### Frontend Tests - `cd frontend && pnpm run validate` - Runs ESLint, stylelint, prettier check, and TypeScript compilation - No unit tests currently implemented in frontend ## Development Workflow 1. **Setup**: Ensure PostgreSQL is running with required extensions 2. **Dependencies**: Run `make pre-ui` to install frontend packages 3. **Development**: Use `make ui-start` for frontend development server 4. **API Development**: Modify GraphQL schema, run `make generate` to update code 5. **Database Changes**: Add migration files to `internal/database/migrations/postgres/` (executed sequentially by filename) 6. **Query Changes**: Modify SQL files in `internal/queries/sql/`, run `make generate-sqlc` to regenerate Go code 7. **Testing**: Run `make lint test it` before committing changes 8. **Build**: Use `make stash-box` for complete production build ## Important Notes - The application requires libvips for image processing on Linux systems - Default admin user (`root`) is created on first run with random password printed to stdout - Frontend development can use API key in `.env.development.local` to bypass login - Integration tests require PostgreSQL (default: `postgres@localhost/stash-box-test?sslmode=disable`) - pHash distance matching requires `pg-spgist_hamming` PostgreSQL extension ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2019 stashapp Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: Makefile ================================================ LDFLAGS := $(LDFLAGS) .PHONY: \ stash-box \ generate \ generate-backend \ generate-ui \ generate-sqlc \ generate-goverter \ generate-dataloaders \ test \ it \ fmt \ lint \ ui \ ui-start \ ui-fmt \ ui-validate \ pre-ui \ clean ifdef OUTPUT OUTPUT := -o $(OUTPUT) endif stash-box: pre-ui generate ui lint build pre-build: ifndef BUILD_DATE $(eval BUILD_DATE := $(shell go run scripts/getDate.go)) endif ifndef GITHASH $(eval GITHASH := $(shell git rev-parse --short HEAD)) endif ifndef STASH_BOX_VERSION $(eval STASH_BOX_VERSION := $(shell git describe --tags --abbrev=0 --exclude latest-develop)) endif ifndef BUILD_TYPE $(eval BUILD_TYPE := LOCAL) endif build: pre-build $(eval LDFLAGS := $(LDFLAGS) -X 'github.com/stashapp/stash-box/internal/api.version=$(STASH_BOX_VERSION)' -X 'github.com/stashapp/stash-box/internal/api.buildstamp=$(BUILD_DATE)' -X 'github.com/stashapp/stash-box/internal/api.githash=$(GITHASH)' -X 'github.com/stashapp/stash-box/internal/api.buildtype=$(BUILD_TYPE)') go build $(OUTPUT) -v -ldflags "$(LDFLAGS) $(EXTRA_LDFLAGS)" ./cmd/stash-box build-release-static: EXTRA_LDFLAGS := -extldflags=-static -s -w build-release-static: build # Regenerates GraphQL files and sqlc code generate: generate-backend generate-ui generate-sqlc clean: @ rm -rf stash-box frontend/node_modules frontend/build dist generate-backend: @ go generate ./... generate-ui: cd frontend && pnpm generate generate-sqlc: sqlc generate generate-goverter: go run github.com/jmattheis/goverter/cmd/goverter gen ./internal/converter/gen generate-dataloaders: cd internal/dataloader; \ go run github.com/vektah/dataloaden UUIDsLoader github.com/gofrs/uuid.UUID "[]github.com/gofrs/uuid.UUID"; \ go run github.com/vektah/dataloaden URLLoader github.com/gofrs/uuid.UUID "[]github.com/stashapp/stash-box/internal/models.URL"; \ go run github.com/vektah/dataloaden TagLoader github.com/gofrs/uuid.UUID "*github.com/stashapp/stash-box/internal/models.Tag"; \ go run github.com/vektah/dataloaden StringsLoader github.com/gofrs/uuid.UUID "[]string"; \ go run github.com/vektah/dataloaden SceneAppearancesLoader github.com/gofrs/uuid.UUID "[]github.com/stashapp/stash-box/internal/models.PerformerScene"; \ go run github.com/vektah/dataloaden PerformerLoader github.com/gofrs/uuid.UUID "*github.com/stashapp/stash-box/internal/models.Performer"; \ go run github.com/vektah/dataloaden ImageLoader github.com/gofrs/uuid.UUID "*github.com/stashapp/stash-box/internal/models.Image"; \ go run github.com/vektah/dataloaden FingerprintsLoader github.com/gofrs/uuid.UUID "[]github.com/stashapp/stash-box/internal/models.Fingerprint"; \ go run github.com/vektah/dataloaden SubmittedFingerprintsLoader github.com/gofrs/uuid.UUID "[]github.com/stashapp/stash-box/internal/models.Fingerprint"; \ go run github.com/vektah/dataloaden BodyModificationsLoader github.com/gofrs/uuid.UUID "[]github.com/stashapp/stash-box/internal/models.BodyModification"; \ go run github.com/vektah/dataloaden TagCategoryLoader github.com/gofrs/uuid.UUID "*github.com/stashapp/stash-box/internal/models.TagCategory"; \ go run github.com/vektah/dataloaden SiteLoader github.com/gofrs/uuid.UUID "*github.com/stashapp/stash-box/internal/models.Site"; \ go run github.com/vektah/dataloaden StudioLoader github.com/gofrs/uuid.UUID "*github.com/stashapp/stash-box/internal/models.Studio"; \ go run github.com/vektah/dataloaden EditLoader github.com/gofrs/uuid.UUID "*github.com/stashapp/stash-box/internal/models.Edit"; \ go run github.com/vektah/dataloaden EditCommentLoader github.com/gofrs/uuid.UUID "*github.com/stashapp/stash-box/internal/models.EditComment"; \ go run github.com/vektah/dataloaden SceneLoader github.com/gofrs/uuid.UUID "*github.com/stashapp/stash-box/internal/models.Scene"; \ go run github.com/vektah/dataloaden BoolsLoader github.com/gofrs/uuid.UUID "bool"; test: go test ./... # Runs the integration tests. -count=1 is used to ensure results are not # cached, which is important if the environment changes it: go test -tags=integration -count=1 ./... # Runs gofmt -w on the project's source code, modifying any files that do not match its style. fmt: go fmt ./... # Runs all configured linuters. golangci-lint needs to be installed locally first. lint: golangci-lint run pre-ui: cd frontend && pnpm install ui: cd frontend && pnpm build ui-start: cd frontend && pnpm start ui-fmt: cd frontend && pnpm format # runs tests and checks on the UI and builds it ui-validate: cd frontend && pnpm run validate # cross-compile- targets should be run within the compiler docker container cross-compile-windows: export GOOS := windows cross-compile-windows: export GOARCH := amd64 cross-compile-windows: export CC := x86_64-w64-mingw32-gcc cross-compile-windows: export CXX := x86_64-w64-mingw32-g++ cross-compile-windows: export CGO_ENABLED = 0 cross-compile-windows: OUTPUT := -o dist/stash-box-windows.exe cross-compile-windows: build-release-static cross-compile-linux: export GOOS := linux cross-compile-linux: export GOARCH := amd64 cross-compile-linux: OUTPUT := -o dist/stash-box-linux cross-compile-linux: export CGO_ENABLED = 1 cross-compile-linux: build cross-compile: make cross-compile-windows make cross-compile-linux ================================================ FILE: README.md ================================================ # stash-box [![Build](https://github.com/stashapp/stash-box/actions/workflows/build.yml/badge.svg?branch=master&event=push)](https://github.com/stashapp/stash-box/actions/workflows/build.yml) [![Open Collective backers](https://img.shields.io/opencollective/backers/stashapp?logo=opencollective)](https://opencollective.com/stashapp) [![Go Report Card](https://goreportcard.com/badge/github.com/stashapp/stash-box)](https://goreportcard.com/report/github.com/stashapp/stash-box) [![Discord](https://img.shields.io/discord/559159668438728723.svg?logo=discord)](https://discord.gg/2TsNFKt) [![GitHub release (latest by date)](https://img.shields.io/github/v/release/stashapp/stash-box?logo=github)](https://github.com/stashapp/stash-box/releases/latest) [![GitHub issues by-label](https://img.shields.io/github/issues-raw/stashapp/stash-box/bounty)](https://github.com/stashapp/stash-box/labels/bounty) Stash-box is an open-source video indexing and metadata API server for porn developed by Stash App. The purpose of stash-box is to provide a community-driven database of porn metadata, similar to what MusicBrainz does for music. The submission and editing of metadata should follow the same principles as MusicBrainz. [Learn more here](https://musicbrainz.org/doc/Editing_FAQ). Installing Stash-box will create an empty database for you to populate. # Canonical community-database If you're a Stash user, you don't need to install stash-box. The Stash community has a server with many titles from which you can pull data. You can get the login information from our guide to [Accessing StashDB](https://guidelines.stashdb.org/docs/faq_getting-started/stashdb/accessing-stashdb/). # Docker install You can find a `docker-compose` file for production deployment [here](docker/production/docker-compose.yml). You can omit Traefik if you don't need a reverse proxy. If you already have PostgreSQL installed, you can install stash-box on its own from [Docker Hub](https://hub.docker.com/r/stashapp/stash-box). # Bare-metal install Stash-box supports macOS, Windows, and Linux. Releases for Windows and Linux can be found [here](https://github.com/stashapp/stash-box/releases). ## Prerequisites To build stash-box on linux [libvips](https://www.libvips.org/) must be installed, as well as gcc. ## Initial setup 1. Run `make` to build the application. 2. Stash-box requires access to a PostgreSQL database server. Suppose stash-box doesn't find a configuration file (defaults to `stash-box-config.yml` in the current directory). In that case, it will generate a default configuration file with a default PostgreSQL connection string (`postgres@localhost/stash-box?sslmode=disable`). You can adjust the connection string as needed. 3. The database must be created and available. If the PostgreSQL user is not a superuser, run `CREATE EXTENSION pg_trgm; CREATE EXTENSION pgcrypto;` by a superuser before rerunning Stash-box. If the schema is not present, it will be created within the database. 4. The `sslmode` parameter is documented [here](https://godoc.org/github.com/lib/pq). Use `sslmode=disable` to not use SSL for the database connection. The default is `require`. 5. After ensuring the database connection and availability, rerun Stash-box. #### Schema migrations and initial Admin user The second time that stash-box is run, stash-box will run the schema migrations to create the required tables. It will also generate a `root` user with a random password and an API key. These credentials are printed once to stdout and are not logged. The system will regenerate the root user on startup if it does not exist. You can force the system to create a new root user by deleting the root user row from the database and restarting Stash-box. You'll need to capture the console output with your Admin user on the first successful StashDB executable start. Otherwise, you will need to allow Postgres to re-create the database before it will re-post a new `root` user. # Stash-box CLI and configuration Stash-box is a tool with command line options to make it easier. To see what options are available, run `stash-box --help` in your terminal. Here's an example of how you can run stash-box locally on port 80: `stash-box --host 127.0.0.1 --port 80` **Note:** This command should work on OSX / Linux. When you start stash-box for the first time, it generates a configuration file called `stash-box-config.yml` in your current working directory. This file contains default settings for stash-box, including: - Host: `0.0.0.0` - Port: `9998` You can change these defaults if needed. For example, if you want to disable the GraphQL playground and cross-domain cookies, you can set `is_production` to `true`. ## API keys and authorization There are two ways to authenticate a user in Stash-box: a session or an API key. 1. Session-based authentication: To log in, send a request to `/login` with the `username` and `password` in plain text as form values. Session-based authentication will set a cookie that is required for all subsequent requests. To log out, send a request to `/logout`. 2. API key authentication: To use an API key, set the `ApiKey` header to the user's API key value. ### Configuration keys | Key | Default | Description | |-----|---------|-------------| | `title` | `Stash-Box` | Title of the instance, used in the page title. | | `require_invite` | `true` | If true, users are required to enter an invite key, generated by existing users to create a new account. | | `require_activation` | `false` | If true, users are required to verify their email address before creating an account. Requires `email_from`, `email_host`, and `host_url` to be set. | | `activation_expiry` | `7200` (2 hours) | The time - in seconds - after which an activation key (emailed to the user for email verification or password reset purposes) expires. | | `email_cooldown` | `300` (5 minutes) | The time - in seconds - that a user must wait before submitting an activation or reset password request for a specific email address. | | `default_user_roles` | `READ`, `VOTE`, `EDIT` | The roles assigned to new users when registering. This field must be expressed as a yaml array. | | `guidelines_url` | (none) | URL to link to a set of guidelines for users contributing edits. Should be in the form of `https://hostname.com`. | | `vote_promotion_threshold` | (none) | Number of approved edits before a user automatically has the `VOTE` role assigned. Leave empty to disable. | | `vote_application_threshold` | `3` | Number of same votes required for immediate application of an edit. Set to zero to disable automatic application. | | `voting_period` | `345600` | Time, in seconds, before a voting period is closed. | | `min_destructive_voting_period` | `172800` | Minimum time, in seconds, that needs to pass before a destructive edit can be immediately applied with sufficient positive votes. | | `vote_cron_interval` | `5m` | Time between runs to close edits whose voting periods have ended. | | `edit_update_limit` | `1` | Number of times an edit can be updated by the creator. | | `email_host` | (none) | Address of the SMTP server. Required to send emails for activation and recovery purposes. | | `email_port` | `25` | Port of the SMTP server. Only STARTTLS is supported. Direct TLS connections are not supported. | | `email_user` | (none) | Username for the SMTP server. Optional. | | `email_password` | (none) | Password for the SMTP server. Optional. | | `email_from` | (none) | Email address from which to send emails. | | `host_url` | (none) | Base URL for the server. Used when sending emails. Should be in the form of `https://hostname.com`. | | `image_location` | (none) | Path to store images, for local image storage. An error will be displayed if this is not set when creating non-URL images. | | `image_backend` | (`file`) | Storage solution for images. Can be set to either `file` or `s3`. | | `image_jpeg_quality` | `75` | Quality setting when resizing JPEG images. Valid values are 0-100. | | `image_max_size` | (none) | Max size of image, if no size is specified. Omit to return full size. | | `image_resizing.enabled` | false | Whether to resize images shown in the frontend. | | `image_resizing.cache_path` | (none) | Folder in which resized images will be saved for later requests. Recommended when resizing is enabled. | | `image_resizing.min_size` | (none) | Only resize images above a certain size | | `userLogFile` | (none) | Path to the user log file, which logs user operations. If not set, then these will be output to stderr. | | `s3.endpoint` | (none) | Hostname to s3 endpoint used for image storage. | | `s3.bucket` | (none) | Name of S3 bucket used to store images. | | `s3.access_key` | (none) | Access key used for authentication. | | `s3.secret ` | (none) | Secret Access key used for authentication. | | `s3.max_dimension` | (none) | If set, a resized copy will be created for any image whose dimensions exceed this number. This copy will be served in place of the original. | | `s3.upload_headers` | (none) | A map of headers to send with each upload request. For example, DigitalOcean requires the `x-amz-acl` header to be set to `public-read` or it does not make the uploaded images available. | | `phash_distance` | 0 | Determines what binary distance is considered a match when querying with a pHash fingeprint. Using more than 8 is not recommended and may lead to large amounts of false positives. **Note**: The [pg-spgist_hamming extension](#phash-distance-matching) must be installed to use distance matching, otherwise you will get errors. | | `favicon_path` | (none) | Location where favicons for linked sites should be stored. Leave empty to disable. | | `draft_time_limit` | (24h) | Time, in seconds, before a draft is deleted. | | `profiler_port` | 0 | Port on which to serve pprof output. Omit to disable entirely. | | `port` | 9998 | Port on which the server runs. When using SSL certificates it should be set to `443`. | | `postgres.max_open_conns` | (0) | Maximum number of concurrent open connections to the database. | | `postgres.max_idle_conns` | (0) | Maximum number of concurrent idle database connections. | | `postgres.conn_max_lifetime` | (0) | Maximum lifetime in minutes before a connection is released. | | `require_scene_draft` | false | Whether to allow scene creation outside of draft submissions. | | `require_tag_role` | false | Whether to require the EditTag role to edit tags. | | `csp` | (none) | Contents of the `Content-Security-Policy` header | | `autocert.enabled` | (none) | Whether to enable [autocert](#lets-encrypt)| | `autocert.cache_dir` | (none) | The directory where autocert certificates are stored. Should be a persisted directory to avoid certificate regeneration on server restart. | | `autocert.domain` | (none) | The domain to generate certificates for.| | `autocert.email` | (none) | A valid email. Will be submitted to Let's Encrypt, but otherwise not made public. | | `mod_audit_retention_days` | 30 | Number of days to retain audit logs of moderator actions. Set `0` to disable. | ## SSL (HTTPS) ### Let's Encrypt Stash-box supports automatic certificate generation from Let's Encrypt. If you want to avoid running behind a reverse proxy - which can cause a certain amount of overhead due to image loading - this is the recommended approach. To use Let's Encrypt, configure the `autocert` config option. As an example: ``` autocert: enabled: true cache_dir: /autocert domain: example.org email: email@example.org ``` To use autocert it needs access to port 80 to respond to Let's Encrypt's challenge. After certificate generation is done, port 80 will redirect to the SSL port. Stash-box will automatically renew the certificate once it has less than 30 days until expiration. ### Self-signed certificates Here's an example of how you can do this using OpenSSL: `openssl req -x509 -newkey rsa:4096 -sha256 -days 7300 -nodes -keyout stash-box.key -out stash-box.crt -extensions san -config <(echo "[req]"; echo distinguished_name=req; echo "[san]"; echo subjectAltName=DNS:stash-box.server,IP:127.0.0.1) -subj /CN=stash-box.server` You might need to modify the command for your specific setup. You can find more information about creating a self-signed certificate with OpenSSL [here](https://stackoverflow.com/questions/10175812/how-to-create-a-self-signed-certificate-with-openssl). Once you've generated the certificate and key pair, make sure they're named `stash-box.crt` and `stash-box.key` respectively, and place them in the same directory as stash-box. When Stash-box detects these files, it will use HTTPS instead of HTTP. ## pHash Distance Matching If you want to enable distance matching for pHashes in stash-box, you'll need to install the [pg-spgist_hamming](https://github.com/fake-name/pg-spgist_hamming) Postgres extension. The recommended way to do this is to use the [docker image](docker/production/postgres/Dockerfile). Still, you can also install it manually by following the build instructions in the pg-spgist_hamming repository. Suppose you install the extension after you've run the migrations. In that case, you'll need to run migration #14 manually to install the extension and add the index. If you don't want to do this, you can wipe the database, and the migrations will run the next time you start stash-box. # Join Our Community We are excited to announce that we have a new home for support, feature requests, and discussions related to Stash and its associated projects. Join our community on the [Discourse forum](https://discourse.stashapp.cc) to connect with other users, share your ideas, and get help from fellow enthusiasts. # Development ## Install * [Go](https://golang.org/dl/), minimum version 1.22. * [golangci-lint](https://golangci-lint.run/) - Linter aggregator * Follow instructions for your platform from [https://golangci-lint.run/usage/install/](https://golangci-lint.run/usage/install/). * Run the linters with `make lint`. * [PNPM](https://pnpm.io/installation) - PNPM package manager ## Commands * `make generate` - Generate Go GraphQL files. This command should be run if the GraphQL schema has changed. * `make ui` - Builds the UI. * `make pre-ui` - Download frontend dependencies * `make build` - Builds the binary * `make test` - Runs the unit tests * `make it` - Runs the unit and integration tests * `make lint` - Run the linter * `make fmt` - Formats and aligns whitespace **Note:** the integration tests run against a temporary sqlite3 database by default. They can be run against a Postgres server by setting the environment variable `POSTGRES_DB` to the Postgres connection string. For example: `postgres@localhost/stash-box-test?sslmode=disable`. **Be aware that the integration tests drop all tables before and after the tests.** ## Frontend development To run the frontend in development mode, run `pnpm start` from the frontend directory. When developing, the API key can be set in `frontend/.env.development.local` to avoid having to log in. When `is_production` is enabled on the server, this is the only way to authorize in the frontend development environment. If the server uses https or runs on a custom port, this also needs to be configured in `.env.development.local`. See `frontend/.env.development.local.shadow` for examples. ## GraphQL playground You can access the GraphQL playground at `host:port/playground`, and the GraphQL interface can be found at `host:port/graphql`. To execute queries add a header with your API key: `{"APIKey":""}`. The API key can be found on your user page in stash-box. ## Building a release 1. Run `make generate` to create generated files if they have been changed. 2. Run `make ui build` to build the executable for your current platform. # FAQ > I have a question that needs to be answered here. * Join the [Discourse forum](https://discourse.stashapp.cc) * Join the [Discord server](https://discord.gg/2TsNFKt), where the community can offer support. * Start a [discussion on GitHub](https://github.com/stashapp/stash-box/discussions) ================================================ FILE: cmd/stash-box/init.go ================================================ package main import ( "fmt" "os" "path/filepath" "strings" "github.com/spf13/pflag" "github.com/spf13/viper" "github.com/stashapp/stash-box/internal/config" "github.com/stashapp/stash-box/pkg/logger" "github.com/stashapp/stash-box/pkg/utils" ) func initConfig(configFilePath *string) { if *configFilePath != "" { dir, name := parseConfigFilePath(*configFilePath) viper.SetConfigName(name) viper.AddConfigPath(dir) } else { viper.SetConfigName(config.GetConfigName()) viper.AddConfigPath(".") } err := viper.ReadInConfig() newConfig := false if err != nil { newConfig = true defaultConfigFilePath := config.GetDefaultConfigFilePath() if *configFilePath != "" { defaultConfigFilePath = *configFilePath } _ = utils.Touch(defaultConfigFilePath) if err = viper.ReadInConfig(); err != nil { panic(err) } } if err = config.InitializeDefaults(); err != nil { panic(err) } initEnvs() if err = viper.ReadInConfig(); err != nil { panic(err) } if err := viper.BindPFlags(pflag.CommandLine); err != nil { logger.Infof("failed to bind flags: %s", err.Error()) } if err = config.Initialize(); err != nil { panic(err) } if newConfig { fmt.Printf(` A new config file has been generated at %s. The database connection string has been defaulted to: %s Please ensure this database is created and available, or change the connection string in the configuration file, then rerun stash-box.`, viper.GetViper().ConfigFileUsed(), config.GetDatabasePath()) os.Exit(0) } missingEmail := config.GetMissingEmailSettings() if len(missingEmail) > 0 { fmt.Printf("RequireActivation is set to true, but the following required settings are missing: %s\n", strings.Join(missingEmail, ", ")) } missingAutocert := config.GetMissingAutocertSettings() if len(missingAutocert) > 0 { fmt.Printf("Autocert is enabled, but the following required settings are missing: %s\n", strings.Join(missingAutocert, ", ")) os.Exit(1) } } func parseConfigFilePath(configFilePath string) (string, string) { dir := filepath.Dir(configFilePath) name := filepath.Base(configFilePath) extension := filepath.Ext(configFilePath) name = strings.TrimSuffix(name, extension) return dir, name } func initEnvs() { viper.SetEnvPrefix("stash_box") viper.AutomaticEnv() _ = viper.BindEnv("host") _ = viper.BindEnv("port") _ = viper.BindEnv("database") } ================================================ FILE: cmd/stash-box/main.go ================================================ package main import ( "context" "net" "github.com/spf13/pflag" "github.com/stashapp/stash-box/frontend" "github.com/stashapp/stash-box/internal/api" "github.com/stashapp/stash-box/internal/config" "github.com/stashapp/stash-box/internal/cron" "github.com/stashapp/stash-box/internal/database" "github.com/stashapp/stash-box/internal/email" "github.com/stashapp/stash-box/internal/image" "github.com/stashapp/stash-box/internal/service" "github.com/stashapp/stash-box/pkg/logger" ) func main() { // Initialize flags pflag.IP("host", net.IPv4(0, 0, 0, 0), "ip address for the host") pflag.Int("port", 9998, "port to serve from") configFilePath := pflag.String("config_file", "", "location of the config file") pflag.Parse() // Initialize config initConfig(configFilePath) // Initialize logger logger.Init(config.GetLogFile(), config.GetUserLogFile(), config.GetLogOut(), config.GetLogLevel()) cleanup := logger.InitTracer() //nolint:errcheck defer cleanup(context.Background()) api.InitializeSession() // Create email manager emailMgr := email.NewManager() db := database.Initialize(config.GetDatabasePath()) fac := service.NewFactory(db, emailMgr) fac.User().CreateSystemUsers(context.Background()) api.Start(*fac, frontend.FS) cron.Init(*fac) if err := image.InitResizer(); err != nil { panic(err) } blockForever() } func blockForever() { c := make(chan struct{}) <-c } ================================================ FILE: docker/build/x86_64/Dockerfile ================================================ # this dockerfile must be built from the top-level stash directory # ie from top=level stash: # docker build -t stash-box/build -f docker/build/x86_64/Dockerfile . FROM golang:1.13.14 as compiler RUN apt-get update && apt-get install -y apt-transport-https RUN curl -sL https://deb.nodesource.com/setup_10.x | bash - RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \ echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list RUN apt-get update && \ apt-get install -y nodejs yarn xz-utils --no-install-recommends || exit 1; \ rm -rf /var/lib/apt/lists/*; WORKDIR / SHELL ["/bin/bash", "-o", "pipefail", "-c"] # copy the ui yarn stuff so that it doesn't get rebuilt every time COPY ./frontend/package.json ./frontend/yarn.lock /stash-box/frontend/ COPY ./Makefile /stash-box/ WORKDIR /stash-box RUN make pre-ui COPY . /stash-box/ ENV GO111MODULE=on RUN make generate RUN make ui RUN make build FROM ubuntu:19.10 as app RUN apt-get update && apt-get -y install ca-certificates COPY --from=compiler /stash-box/stash-box /usr/bin/ EXPOSE 9998 CMD ["stash-box", "--config_file", "/root/.stash-box/stash-box-config.yml"] ================================================ FILE: docker/build/x86_64/db/initdb.sh ================================================ #!/bin/bash set -e psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" -c 'CREATE DATABASE "stash-box";' && \ psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "stash-box" -c 'CREATE EXTENSION pg_trgm; CREATE EXTENSION pgcrypto;' ================================================ FILE: docker/build/x86_64/docker-compose.yml ================================================ # APPNICENAME=Stash-box # APPDESCRIPTION=Stash App's own OpenSource video indexing and Perceptual Hashing MetaData API for porn version: '3.4' services: db: image: postgres:12.3 restart: always environment: POSTGRES_PASSWORD: stash-box-db volumes: - ./stash-box-data/data:/var/lib/postgresql/data - ./db:/docker-entrypoint-initdb.d stash-box: image: stash-box/build:latest restart: always depends_on: - "db" environment: STASH_BOX_DATABASE: postgres:stash-box-db@db/stash-box?sslmode=disable ports: - 9998:9998 volumes: - /etc/localtime:/etc/localtime:ro ## Adjust below paths (the left part) to your liking. ## E.g. you can change ./config:/root/.stash to ./stash:/root/.stash ## Keep configs here. - ./config:/root/.stash-box ================================================ FILE: docker/ci/x86_64/Dockerfile ================================================ # must be built from /dist directory FROM ubuntu:24.04 as app LABEL MAINTAINER="https://discord.gg/Uz29ny" RUN apt-get update && apt-get install -y libvips COPY stash-box-linux /usr/bin/stash-box EXPOSE 9998 CMD ["stash-box", "--config_file", "/root/.stash-box/stash-box-config.yml"] ================================================ FILE: docker/ci/x86_64/docker_push.sh ================================================ #!/bin/bash DOCKER_TAG=$1 # must build the image from dist directory echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin docker build -t stashapp/stash-box:$DOCKER_TAG -f ./docker/ci/x86_64/Dockerfile ./dist docker push stashapp/stash-box:$DOCKER_TAG ================================================ FILE: docker/production/docker-compose.yml ================================================ version: '3.8' services: postgres: container_name: postgres build: ./postgres restart: always environment: POSTGRES_USER: POSTGRES_PASSWORD: POSTGRES_DB: volumes: - /pgdata:/var/lib/postgresql/data stash-box: container_name: stash-box image: stashapp/stash-box:development restart: always logging: driver: "json-file" options: max-file: "10" max-size: "2m" links: - postgres volumes: - :/root/.stash-box labels: - traefik.http.routers.stash-box.rule=Host(``) - traefik.http.routers.stash-box.tls=true - traefik.http.routers.stash-box.tls.certresolver=stash-box - traefik.port=9998 traefik: container_name: traefik image: traefik:2.3 restart: always ports: - 80:80 - 443:443 command: - "--entrypoints.web.address=:80" - "--entrypoints.websecure.address=:443" - "--entryPoints.web.http.redirections.entryPoint.to=websecure" - "--entryPoints.web.http.redirections.entryPoint.scheme=https" - "--providers.docker=true" - "--certificatesResolvers.stash-box.acme.email=" - "--certificatesResolvers.stash-box.acme.storage=/acme.json" - "--certificatesresolvers.stash-box.acme.tlschallenge=true" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - /traefik/acme.json:/acme.json ================================================ FILE: docker/production/postgres/Dockerfile ================================================ FROM postgres:18 # Build and install pg-spgist_hamming (pHash matching) RUN apt-get update \ && apt-get install -y --no-install-recommends make gcc postgresql-server-dev-18 git ca-certificates \ && git clone --depth 1 https://github.com/fake-name/pg-spgist_hamming.git /tmp/pg-spgist_hamming \ && make -C /tmp/pg-spgist_hamming/bktree \ && make -C /tmp/pg-spgist_hamming/bktree install \ && rm -rf /tmp/pg-spgist_hamming /var/lib/apt/lists/* \ && apt-get purge -y --auto-remove make gcc postgresql-server-dev-18 git # Install pg_search (ParadeDB full-text search) RUN apt-get update \ && apt-get install -y --no-install-recommends curl ca-certificates \ && curl -fLo /tmp/pg_search.deb \ https://github.com/paradedb/paradedb/releases/download/v0.21.8/postgresql-18-pg-search_0.21.8-1PARADEDB-trixie_amd64.deb \ && apt-get install -y /tmp/pg_search.deb \ && rm -f /tmp/pg_search.deb \ && apt-get purge -y curl \ && rm -rf /var/lib/apt/lists/* ================================================ FILE: frontend/.gitattributes ================================================ src/**/*.ts* text eol=lf ================================================ FILE: frontend/.gitignore ================================================ .idea/ dist/ node_modules/ src/**/*.jsx tests/__coverage__/ tests/**/*.jsx .eslintcache .env*.local build *.swp ================================================ FILE: frontend/.nvmrc ================================================ 24 ================================================ FILE: frontend/README.md ================================================ # Stash-box frontend This project builds the frontend for the stash-box server. It can be used to build the static bundle for the go server, or be run standalone for development purposes. ## Setup / Installing Make sure your environment is up to date: - node >= `22` - pnpm >= `9` For `node` installation instructions, please see the websites for [node.js](https://nodejs.org/en/download/). `PNPM` can usually be installed by running `corepack enable pnpm`. For other options, see the [PNPM website](https://pnpm.io/installation). Install dependencies ```shell pnpm i ``` ## GraphQL development If any queries/mutations or the schema on the server is updated, the Typescript types can be updated with: ```shell pnpm generate ``` ## Running ### Local development server The API key can be set in the environment configuration. To do so, you will need to initialize the environment configuration: ```shell cp .env.development.local.shadow .env.development.local ``` Fill in the `VITE_APIKEY` variable in `.env.development.local` with the API key for the user. Run the local development server: ```shell pnpm start ``` The server will by default start on [http://localhost:3001](http://localhost:3001) and will automatically be updated whenever any changes are made. The port can be changed by uncommenting the `PORT` entry and setting the value in the `.env.development.local` file. Run the linter: ```shell pnpm lint ``` Run the code formatter: ```shell pnpm format ``` Build the release bundle: ```shell pnpm build ``` Run the validation (before submitting a Pull Request) ```shell pnpm validate ``` ================================================ FILE: frontend/biome.json ================================================ { "$schema": "https://biomejs.dev/schemas/2.2.0/schema.json", "vcs": { "enabled": false, "clientKind": "git", "useIgnoreFile": false }, "files": { "ignoreUnknown": false, "includes": ["src/**", "!src/graphql/types.ts"] }, "formatter": { "enabled": true, "indentStyle": "space", "indentWidth": 2 }, "javascript": { "formatter": { "quoteStyle": "double" }, "globals": [] }, "linter": { "rules": { "a11y": { "useSemanticElements": "off" }, "correctness": { "useUniqueElementIds": "off" } } }, "assist": { "enabled": true, "actions": { "source": { "organizeImports": "on" } } } } ================================================ FILE: frontend/codegen.yml ================================================ overwrite: true schema: "../graphql/schema/**/*.graphql" documents: "src/graphql/**/*.gql" generates: src/graphql/types.ts: plugins: - typescript - typescript-operations - typed-document-node config: dedupeOperationSuffix: true scalars: Date: string DateTime: string Time: string Upload: File FingerprintHash: string namingConvention: enumValues: change-case-all#upperCase nonOptionalTypename: true ================================================ FILE: frontend/embed.go ================================================ package frontend import "embed" //go:embed build var FS embed.FS ================================================ FILE: frontend/index.html ================================================ {{.}}
================================================ FILE: frontend/package.json ================================================ { "name": "stash-box-frontend", "version": "0.1.0", "description": "Stash-box", "license": "MIT", "scripts": { "start": "vite --host", "build": "vite build", "validate": "pnpm lint && pnpm format-check && tsc --noEmit", "lint": "pnpm biome lint src", "generate": "graphql-codegen --config codegen.yml", "format": "pnpm biome format --write", "format-check": "pnpm biome format", "analyze": "analyze=true vite build" }, "engines": { "node": ">=24", "yarn": "Please use pnpm", "npm": "Please use pnpm" }, "packageManager": "pnpm@9.0.5", "devDependencies": { "@biomejs/biome": "^2.4.10", "@graphql-codegen/cli": "^6.2.1", "@graphql-codegen/typed-document-node": "^6.1.7", "@graphql-codegen/typescript": "^5.0.9", "@graphql-codegen/typescript-operations": "^5.0.9", "@graphql-typed-document-node/core": "^3.2.0", "@types/apollo-upload-client": "^19.0.0", "@types/lodash-es": "^4.17.12", "@types/node": "~24", "@types/react": "^18.3.1", "@types/react-dom": "^18.3.1", "@types/react-helmet": "^6.1.11", "@vitejs/plugin-react": "^6.0.1", "rollup-plugin-analyzer": "^4.0.0", "sass": "~1.77.6", "typescript": "~6.0.2", "vite": "^8.0.3", "vite-plugin-graphql-loader": "^5.0.1" }, "dependencies": { "@apollo/client": "4.1.6", "@fortawesome/fontawesome-svg-core": "^7.1.0", "@fortawesome/free-regular-svg-icons": "^7.1.0", "@fortawesome/free-solid-svg-icons": "^7.1.0", "@fortawesome/react-fontawesome": "^3.1.1", "@hookform/lenses": "^0.9.0", "@hookform/resolvers": "5.2.2", "apollo-upload-client": "^19.0.0", "bootstrap": "5.2.3", "classnames": "^2.5.1", "graphql": "^16.13.2", "graphql-tag": "^2.12.6", "i18n-iso-countries": "^7.14.0", "lodash-es": "^4.18.1", "p-debounce": "^5.1.0", "query-string": "^9.3.1", "react": "^18.3.1", "react-bootstrap": "^2.10.10", "react-bootstrap-typeahead": "^6.4.1", "react-dom": "^18.3.1", "react-helmet": "^6.1.0", "react-hook-form": "7.72.1", "react-markdown": "^10.1.0", "react-responsive-carousel": "^3.2.23", "react-router-dom": "^6.30.2", "react-select": "5.8.3", "rehype-external-links": "^3.0.0", "remark-breaks": "^4.0.0", "remark-gfm": "^4.0.1", "temporal-polyfill": "^0.3.2", "yup": "1.0.1" }, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] } } ================================================ FILE: frontend/src/App.scss ================================================ @import "./styles/theme"; @import "./hooks/toast"; @import "./pages/home/styles"; @import "./pages/users/styles"; @import "./pages/notifications/styles"; @import "./pages/performers/styles"; @import "./pages/scenes/styles"; @import "./pages/scenes/sceneForm/styles"; @import "./pages/studios/styles"; @import "./pages/search/search"; @import "./components/checkboxSelect/styles"; @import "./components/editCard/styles"; @import "./components/form/styles"; @import "./components/fragments/styles"; @import "./components/imageCarousel/styles"; @import "./components/imageChangeRow/styles"; @import "./components/list/styles"; @import "./components/performerCard/styles"; @import "./components/performerSelect/styles"; @import "./components/sceneCard/styles"; @import "./components/searchField/styles"; @import "./components/studioSelect/styles"; @import "./components/tagFilter/styles"; @import "./components/tagSelect/styles"; @import "./components/editImages/styles"; @import "./components/urlInput/styles"; @import "./components/image/styles"; @import "react-bootstrap-typeahead/css/Typeahead.css"; /* this is a bit of a hack, because we can't supply direct class names to the react-select controls */ /* stylelint-disable selector-class-pattern */ .react-select__control { background-color: $secondary; border-color: $secondary; color: $text-color; cursor: pointer; .react-select__single-value, .react-select__input { color: black; } .react-select__multi-value { background-color: $muted-gray; color: $text-color; } } div.react-select__menu { background-color: $secondary; color: $text-color; z-index: 2; .react-select__option { color: $text-color; } .react-select__option--is-focused { background-color: #8a9ba826; cursor: pointer; } } .LoginPrompt { height: 70vh; width: 960px; margin-left: auto; margin-right: auto; display: flex; a { color: $link-color; } } .bullet-separator { &::before { content: "\2022"; margin: 0 0.5rem; } } .PendingEditTab { color: $warning !important; } .MainContent { padding-top: 2rem; padding-bottom: 1rem; } .NarrowPage { margin: auto; max-width: 1200px; } .NotificationBadge { color: white; &:active, &:hover { color: var(--bs-gray-500); } } ================================================ FILE: frontend/src/App.tsx ================================================ import type { FC } from "react"; import { ApolloProvider } from "@apollo/client/react"; import { BrowserRouter, Route, Routes } from "react-router-dom"; import { config as fontAwesomeConfig } from "@fortawesome/fontawesome-svg-core"; import Main from "src/Main"; import createClient from "src/utils/createClient"; import Pages from "src/pages"; import Title from "src/components/title"; import { ToastProvider } from "src/hooks/useToast"; fontAwesomeConfig.autoAddCss = false; import "./App.scss"; import "@fortawesome/fontawesome-svg-core/styles.css"; const client = createClient(); const App: FC = () => ( <Pages /> </Main> } /> </Routes> </ToastProvider> </BrowserRouter> </ApolloProvider> ); export default App; ================================================ FILE: frontend/src/Login.tsx ================================================ import { type FC, useState } from "react"; import { Link, useLocation, useNavigate } from "react-router-dom"; import { useForm } from "react-hook-form"; import { Button, Col, Form, Row } from "react-bootstrap"; import { yupResolver } from "@hookform/resolvers/yup"; import * as yup from "yup"; import cx from "classnames"; import { ROUTE_REGISTER, ROUTE_FORGOT_PASSWORD } from "src/constants/route"; import { getPlatformURL, getCredentialsSetting } from "src/utils/createClient"; import "./App.scss"; import { useCurrentUser } from "./hooks"; const schema = yup.object({ username: yup.string().required("Username is required"), password: yup.string().required("Password is required"), }); type LoginFormData = yup.InferType<typeof schema>; const Messages: Record<string, string> = { "password-reset": "Password successfully reset", "account-created": "Account successfully created", }; const Login: FC = () => { const [loading, setLoading] = useState(false); const location = useLocation(); const navigate = useNavigate(); const [loginError, setLoginError] = useState(""); const msg = new URLSearchParams(location.search).get("msg"); const redirect = new URLSearchParams(location.search).get("redirect"); const { isAuthenticated } = useCurrentUser(); const { register, handleSubmit, formState: { errors }, } = useForm<LoginFormData>({ resolver: yupResolver(schema), }); if (isAuthenticated) navigate("/"); const onSubmit = async (formData: LoginFormData) => { setLoading(true); const body = new FormData(); body.append("username", formData.username); body.append("password", formData.password); const res = await fetch(`${getPlatformURL()}login`, { method: "POST", body, credentials: getCredentialsSetting(), }).finally(() => setLoading(false)); const returnURL = decodeURIComponent(redirect ?? "") || "/"; if (res.ok) window.location.replace(returnURL); else setLoginError("Access denied"); }; return ( <div className="LoginPrompt"> <Form className="align-self-center col-4 mx-auto" onSubmit={handleSubmit(onSubmit)} > <Form.Floating> <Form.Control className={cx({ "is-invalid": errors?.username })} placeholder="Username" {...register("username")} /> <Form.Label>Username</Form.Label> <div className="invalid-feedback text-end"> {errors?.username?.message} </div> </Form.Floating> <Form.Floating className="my-3"> <Form.Control type="password" className={cx({ "is-invalid": errors?.password })} placeholder="Password" {...register("password")} /> <Form.Label>Password</Form.Label> <div className="invalid-feedback text-end"> {errors?.password?.message} </div> </Form.Floating> <Row> <Col xs={9}> <div> <Link to={ROUTE_REGISTER}> <small>Register</small> </Link> </div> <div> <Link to={ROUTE_FORGOT_PASSWORD}> <small>Forgot Password</small> </Link> </div> </Col> <Col xs={3} className="d-flex justify-content-end"> <div> <Button type="submit" className="login-button" disabled={loading}> Login </Button> </div> </Col> </Row> <Row> <p className="col text-end text-danger">{loginError}</p> </Row> <Row> <p className="col text-end text-success"> {Messages[msg ?? ""] ?? ""} </p> </Row> </Form> </div> ); }; export default Login; ================================================ FILE: frontend/src/Main.tsx ================================================ import { type FC, useEffect } from "react"; import { Navbar, Nav, Button, Badge } from "react-bootstrap"; import { NavLink, useLocation, useNavigate, Link } from "react-router-dom"; import { faBell, faBook, faUser } from "@fortawesome/free-solid-svg-icons"; import { faBell as faBellOutlined } from "@fortawesome/free-regular-svg-icons"; import SearchField, { SearchType } from "src/components/searchField"; import { getPlatformURL, getCredentialsSetting } from "src/utils/createClient"; import { userHref, setCachedUser, canEdit, isAdmin } from "src/utils"; import { useAuth } from "src/hooks"; import { Icon } from "src/components/fragments"; import { useConfig, useUnreadNotificationsCount } from "src/graphql"; import { ROUTE_SCENES, ROUTE_PERFORMERS, ROUTE_TAGS, ROUTE_STUDIOS, ROUTE_EDITS, ROUTE_LOGOUT, ROUTE_LOGIN, ROUTE_USERS, ROUTE_ACTIVATE, ROUTE_RESET_PASSWORD, ROUTE_HOME, ROUTE_REGISTER, ROUTE_FORGOT_PASSWORD, ROUTE_SITES, ROUTE_DRAFTS, ROUTE_NOTIFICATIONS, ROUTE_AUDITS, } from "src/constants/route"; import AuthContext from "./context"; interface Props { children?: React.ReactNode; } const Main: FC<Props> = ({ children }) => { const location = useLocation(); const navigate = useNavigate(); const { loading, user } = useAuth(); const { data: unreadNotifications } = useUnreadNotificationsCount(); const notificationCount = unreadNotifications?.getUnreadNotificationCount || null; const { data: configData } = useConfig(); const guidelinesURL = configData?.getConfig.guidelines_url; useEffect(() => { if (loading || user) return; if ( location.pathname !== ROUTE_ACTIVATE && location.pathname !== ROUTE_REGISTER && location.pathname !== ROUTE_LOGIN && location.pathname !== ROUTE_FORGOT_PASSWORD && location.pathname !== ROUTE_RESET_PASSWORD ) { const redirect = location.pathname === "/" ? "" : `?redirect=${encodeURIComponent(location.pathname)}`; navigate(`${ROUTE_LOGIN}${redirect}`); } }, [loading, user, location, navigate]); const contextValue = { authenticated: user !== undefined, user, }; if (!contextValue.authenticated) return ( <AuthContext.Provider value={contextValue}> {children} </AuthContext.Provider> ); const handleLogout = async () => { const res = await fetch(`${getPlatformURL()}logout`, { credentials: getCredentialsSetting(), }); setCachedUser(); if (res.ok) window.location.href = ROUTE_LOGIN; return false; }; const renderUserNav = () => contextValue.authenticated && contextValue.user && ( <> <Link to={ROUTE_NOTIFICATIONS}> <Button variant="link" className="NotificationBadge"> <Icon icon={notificationCount ? faBell : faBellOutlined} /> {notificationCount && ( <Badge bg="danger" className="ms-1"> {notificationCount} </Badge> )} </Button> </Link> <NavLink to={userHref(contextValue.user)} className="nav-link ms-auto me-2" > <Icon icon={faUser} className="me-2" /> {contextValue.user.name} </NavLink> {isAdmin(user) && ( <NavLink to={ROUTE_USERS} className="nav-link"> Users </NavLink> )} <NavLink to={ROUTE_LOGOUT} onClick={handleLogout} className="nav-link me-4" > Logout </NavLink> </> ); return ( <div> <Navbar bg="dark" variant="dark" className="px-4"> <Nav className="me-auto"> <NavLink to={ROUTE_HOME} className="nav-link"> Home </NavLink> <NavLink to={ROUTE_PERFORMERS} className="nav-link"> Performers </NavLink> <NavLink to={ROUTE_SCENES} className="nav-link"> Scenes </NavLink> <NavLink to={ROUTE_STUDIOS} className="nav-link"> Studios </NavLink> <NavLink to={ROUTE_TAGS} className="nav-link"> Tags </NavLink> <NavLink to={ROUTE_EDITS} className="nav-link"> Edits </NavLink> {canEdit(user) && ( <NavLink to={ROUTE_DRAFTS} className="nav-link"> Drafts </NavLink> )} {isAdmin(user) && ( <> <NavLink to={ROUTE_SITES} className="nav-link"> Sites </NavLink> <NavLink to={ROUTE_AUDITS} className="nav-link"> Audits </NavLink> </> )} {guidelinesURL && ( <a href={guidelinesURL} target="_blank" rel="noopener noreferrer" className="nav-link" > <Icon icon={faBook} className="mx-2" /> Guidelines </a> )} </Nav> <Nav className="align-items-center"> {contextValue.authenticated && renderUserNav()} <SearchField searchType={SearchType.Combined} nav showAllLink /> </Nav> </Navbar> <AuthContext.Provider value={contextValue}> <main className="MainContent container-fluid">{children}</main> </AuthContext.Provider> </div> ); }; export default Main; ================================================ FILE: frontend/src/components/amendableEditCard/AmendableChangeRow.tsx ================================================ import type { FC } from "react"; import { Col, Row, Button } from "react-bootstrap"; import { faXmark, faUndo } from "@fortawesome/free-solid-svg-icons"; import cx from "classnames"; import { Icon } from "src/components/fragments"; import { useAmendment } from "./AmendmentContext"; export interface AmendableChangeRowProps { name?: string; field: string; newValue?: string | number | null; oldValue?: string | number | null; showDiff?: boolean; } const AmendableChangeRow: FC<AmendableChangeRowProps> = ({ name, field, newValue, oldValue, showDiff = false, }) => { const { state, clearField, restoreField } = useAmendment(); const isRemoved = state.removedFields.has(field); if (!name || (!newValue && !oldValue)) return null; return ( <Row className={cx("mb-2", { "opacity-50 text-decoration-line-through": isRemoved, })} > <b className="col-2 text-end pt-1">{name}</b> {showDiff && ( <Col xs={4}> <div className="EditDiff bg-danger">{oldValue}</div> </Col> )} <Col xs={showDiff ? 4 : 8}> <div className={cx("EditDiff", { "bg-success": showDiff })}> {newValue} </div> </Col> <Col xs={2} className="text-end"> {!isRemoved && ( <Button variant="danger" size="sm" onClick={() => clearField(field)} title={`Remove ${name} change`} > <Icon icon={faXmark} /> </Button> )} {isRemoved && ( <Button variant="secondary" size="sm" onClick={() => restoreField(field)} title={`Restore ${name} change`} > <Icon icon={faUndo} /> </Button> )} </Col> </Row> ); }; export default AmendableChangeRow; ================================================ FILE: frontend/src/components/amendableEditCard/AmendableImageChangeRow.tsx ================================================ import type { FC } from "react"; import { Col, Row, Button } from "react-bootstrap"; import { faXmark, faUndo } from "@fortawesome/free-solid-svg-icons"; import cx from "classnames"; import ImageComponent from "src/components/image"; import { Icon } from "src/components/fragments"; import { useAmendment } from "./AmendmentContext"; type Image = { height: number; id: string; url: string; width: number; }; const CLASSNAME = "ImageChangeRow"; const CLASSNAME_IMAGE = `${CLASSNAME}-image`; export interface AmendableImageChangeRowProps { field: string; newImages?: (Image | null)[] | null; oldImages?: (Image | null)[] | null; showDiff?: boolean; } const AmendableImageChangeRow: FC<AmendableImageChangeRowProps> = ({ field, newImages, oldImages, showDiff = false, }) => { const { state, clearAddedItem, clearRemovedItem, restoreAddedItem, restoreRemovedItem, } = useAmendment(); const removedAddedIndices = state.removedAddedItems.get(field); const removedRemovedIndices = state.removedRemovedItems.get(field); if ((newImages ?? []).length === 0 && (oldImages ?? []).length === 0) return null; return ( <Row className={CLASSNAME}> <b className="col-2 text-end">Images</b> {showDiff && ( <Col xs={4}> {(oldImages ?? []).length > 0 && ( <> <h6>Removed</h6> <div className={CLASSNAME}> {(oldImages ?? []).map((image, index) => { const isRemoved = removedRemovedIndices?.has(index); return ( <div key={image?.id ?? `deleted-${index}`} className={cx("d-flex align-items-start mb-2", { "opacity-50": isRemoved, })} > {image === null ? ( <img className={CLASSNAME_IMAGE} alt="Deleted" /> ) : ( <div className={CLASSNAME_IMAGE}> <ImageComponent images={image} alt="" size="full" /> <div className="text-center"> {image.width} x {image.height} </div> </div> )} <div className="ms-2"> {!isRemoved && ( <Button variant="danger" size="sm" onClick={() => clearRemovedItem(field, index)} title="Remove this image change from the edit" > <Icon icon={faXmark} /> </Button> )} {isRemoved && ( <Button variant="secondary" size="sm" onClick={() => restoreRemovedItem(field, index)} title="Restore this image" > <Icon icon={faUndo} /> </Button> )} </div> </div> ); })} </div> </> )} </Col> )} <Col xs={showDiff ? 4 : 8}> {(newImages ?? []).length > 0 && ( <> {showDiff && <h6>Added</h6>} <div className={CLASSNAME}> {(newImages ?? []).map((image, index) => { const isRemoved = removedAddedIndices?.has(index); return ( <div key={image?.id ?? `deleted-${index}`} className={cx("d-flex align-items-start mb-2", { "opacity-50": isRemoved, })} > {image === null ? ( <img className={CLASSNAME_IMAGE} alt="Deleted" /> ) : ( <div className={CLASSNAME_IMAGE}> <ImageComponent images={image} alt="" size="full" /> <div className="text-center"> {image.width} x {image.height} </div> </div> )} <div className="ms-2"> {!isRemoved && ( <Button variant="danger" size="sm" onClick={() => clearAddedItem(field, index)} title="Remove this image from the edit" > <Icon icon={faXmark} /> </Button> )} {isRemoved && ( <Button variant="secondary" size="sm" onClick={() => restoreAddedItem(field, index)} title="Restore this image" > <Icon icon={faUndo} /> </Button> )} </div> </div> ); })} </div> </> )} </Col> <Col xs={2} /> </Row> ); }; export default AmendableImageChangeRow; ================================================ FILE: frontend/src/components/amendableEditCard/AmendableLinkedChangeRow.tsx ================================================ import type { FC } from "react"; import { Link } from "react-router-dom"; import { Col, Row, Button } from "react-bootstrap"; import { faXmark, faUndo } from "@fortawesome/free-solid-svg-icons"; import cx from "classnames"; import { Icon } from "src/components/fragments"; import { useAmendment } from "./AmendmentContext"; interface Change { name: string | null | undefined; link: string | null | undefined; } interface AmendableLinkedChangeRowProps { name: string; field: string; oldEntity?: Change | null; newEntity?: Change | null; showDiff?: boolean; } const AmendableLinkedChangeRow: FC<AmendableLinkedChangeRowProps> = ({ name, field, newEntity, oldEntity, showDiff = false, }) => { const { state, clearField, restoreField } = useAmendment(); const isRemoved = state.removedFields.has(field); function getValue(value: Change | null | undefined) { if (!value?.name) { return; } if (!value.link) { return value.name; } return <Link to={value.link}>{value.name}</Link>; } if (!newEntity?.link && !oldEntity?.link) return null; return ( <Row className={cx("mb-2", { "opacity-50 text-decoration-line-through": isRemoved, })} > <b className="col-2 text-end pt-1">{name}</b> {showDiff && ( <Col xs={4} className="ms-auto" key={oldEntity?.name}> <div className="EditDiff bg-danger">{getValue(oldEntity)}</div> </Col> )} <Col xs={showDiff ? 4 : 8} key={newEntity?.name}> <div className={cx("EditDiff", { "bg-success": showDiff })}> {getValue(newEntity)} </div> </Col> <Col xs={2} className="text-end"> {!isRemoved && ( <Button variant="danger" size="sm" onClick={() => clearField(field)} title={`Remove ${name} change`} > <Icon icon={faXmark} /> </Button> )} {isRemoved && ( <Button variant="secondary" size="sm" onClick={() => restoreField(field)} title={`Restore ${name} change`} > <Icon icon={faUndo} /> </Button> )} </Col> </Row> ); }; export default AmendableLinkedChangeRow; ================================================ FILE: frontend/src/components/amendableEditCard/AmendableListChangeRow.tsx ================================================ import type { PropsWithChildren } from "react"; import { Col, Row, Button } from "react-bootstrap"; import { faXmark, faUndo } from "@fortawesome/free-solid-svg-icons"; import cx from "classnames"; import { Icon } from "src/components/fragments"; import { useAmendment } from "./AmendmentContext"; interface AmendableListChangeRowProps<T> { added?: T[] | null; removed?: T[] | null; renderItem: (o: T) => JSX.Element | undefined; getKey: (o: T) => string; name: string; field: string; showDiff?: boolean; } const CLASSNAME = "ListChangeRow"; // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-constraint const AmendableListChangeRow = <T,>({ added, removed, name, field, getKey, renderItem, showDiff, }: PropsWithChildren<AmendableListChangeRowProps<T>>) => { const { state, clearAddedItem, clearRemovedItem, restoreAddedItem, restoreRemovedItem, } = useAmendment(); const removedAddedIndices = state.removedAddedItems.get(field); const removedRemovedIndices = state.removedRemovedItems.get(field); if ((added ?? []).length === 0 && (removed ?? []).length === 0) return null; return ( <Row className={`${CLASSNAME}-${name}`}> <b className="col-2 text-end">{name}</b> {showDiff && ( <Col xs={4}> {(removed ?? []).length > 0 && ( <> <h6>Removed</h6> <div className={CLASSNAME}> <ul> {(removed ?? []).map((u, index) => { const isRemoved = removedRemovedIndices?.has(index); return ( <li key={getKey(u)} className={cx("d-flex align-items-center", { "opacity-50 text-decoration-line-through": isRemoved, })} > <span className="flex-grow-1">{renderItem(u)}</span> {!isRemoved && ( <Button variant="danger" size="sm" className="ms-2" onClick={() => clearRemovedItem(field, index)} title="Remove this item from the edit" > <Icon icon={faXmark} /> </Button> )} {isRemoved && ( <Button variant="secondary" size="sm" className="ms-2" onClick={() => restoreRemovedItem(field, index)} title="Restore this item" > <Icon icon={faUndo} /> </Button> )} </li> ); })} </ul> </div> </> )} </Col> )} <Col xs={showDiff ? 4 : 8}> {(added ?? []).length > 0 && ( <> {showDiff && <h6>Added</h6>} <div className={CLASSNAME}> <ul> {(added ?? []).map((u, index) => { const isRemoved = removedAddedIndices?.has(index); return ( <li key={getKey(u)} className={cx("d-flex align-items-center", { "opacity-50 text-decoration-line-through": isRemoved, })} > <span className="flex-grow-1">{renderItem(u)}</span> {!isRemoved && ( <Button variant="danger" size="sm" className="ms-2" onClick={() => clearAddedItem(field, index)} title="Remove this item from the edit" > <Icon icon={faXmark} /> </Button> )} {isRemoved && ( <Button variant="secondary" size="sm" className="ms-2" onClick={() => restoreAddedItem(field, index)} title="Restore this item" > <Icon icon={faUndo} /> </Button> )} </li> ); })} </ul> </div> </> )} </Col> <Col xs={2} /> </Row> ); }; export default AmendableListChangeRow; ================================================ FILE: frontend/src/components/amendableEditCard/AmendableModifyEdit.tsx ================================================ import type { FC } from "react"; import { Col, Row, Button } from "react-bootstrap"; import { faCheck, faXmark, faEdit, faUndo, } from "@fortawesome/free-solid-svg-icons"; import cx from "classnames"; import type { GenderEnum, EthnicityEnum, BreastTypeEnum, EditFragment, HairColorEnum, EyeColorEnum, } from "src/graphql"; import { formatDuration, getCountryByISO, isTagEdit, isPerformerEdit, formatBodyModification, isStudioEdit, isSceneEdit, studioHref, categoryHref, compareByName, } from "src/utils"; import { EthnicityTypes, HairColorTypes, EyeColorTypes, BreastTypes, GenderTypes, } from "src/constants"; import { Icon } from "src/components/fragments"; import AmendableChangeRow from "./AmendableChangeRow"; import AmendableListChangeRow from "./AmendableListChangeRow"; import AmendableImageChangeRow from "./AmendableImageChangeRow"; import AmendableURLChangeRow from "./AmendableURLChangeRow"; import AmendableLinkedChangeRow from "./AmendableLinkedChangeRow"; import { renderPerformer, renderTag, renderFingerprint, } from "src/components/editCard/renderEntity"; import type { PerformerDetails, OldPerformerDetails, SceneDetails, OldSceneDetails, StudioDetails, OldStudioDetails, TagDetails, OldTagDetails, } from "src/components/editCard/ModifyEdit"; import { useAmendment } from "./AmendmentContext"; type Details = EditFragment["details"]; type OldDetails = EditFragment["old_details"]; type Options = EditFragment["options"]; // Special component for Bra Size which combines band_size and cup_size const AmendableBraSizeRow: FC<{ newBandSize?: number | null; newCupSize?: string | null; oldBandSize?: number | null; oldCupSize?: string | null; showDiff: boolean; }> = ({ newBandSize, newCupSize, oldBandSize, oldCupSize, showDiff }) => { const { state, clearField, restoreField } = useAmendment(); const isRemoved = state.removedFields.has("band_size") || state.removedFields.has("cup_size"); const newValue = `${newBandSize || ""}${newCupSize ?? ""}`; const oldValue = `${oldBandSize || ""}${oldCupSize ?? ""}`; if (!newValue && !oldValue) return null; const handleClear = () => { clearField("band_size"); clearField("cup_size"); }; const handleRestore = () => { restoreField("band_size"); restoreField("cup_size"); }; return ( <Row className={cx("mb-2", { "opacity-50 text-decoration-line-through": isRemoved, })} > <b className="col-2 text-end pt-1">Bra Size</b> {showDiff && ( <Col xs={4}> <div className="EditDiff bg-danger">{oldValue}</div> </Col> )} <Col xs={showDiff ? 4 : 8}> <div className={cx("EditDiff", { "bg-success": showDiff })}> {newValue} </div> </Col> <Col xs={2} className="text-end"> {!isRemoved && ( <Button variant="danger" size="sm" onClick={handleClear} title="Remove Bra Size change" > <Icon icon={faXmark} /> </Button> )} {isRemoved && ( <Button variant="secondary" size="sm" onClick={handleRestore} title="Restore Bra Size change" > <Icon icon={faUndo} /> </Button> )} </Col> </Row> ); }; const renderAmendableTagDetails = ( tagDetails: TagDetails, oldTagDetails: OldTagDetails | undefined, showDiff: boolean, ) => ( <> <AmendableChangeRow name="Name" field="name" newValue={tagDetails.name} oldValue={oldTagDetails?.name} showDiff={showDiff} /> <AmendableChangeRow name="Description" field="description" newValue={tagDetails.description} oldValue={oldTagDetails?.description} showDiff={showDiff} /> <AmendableLinkedChangeRow name="Category" field="category_id" newEntity={{ name: tagDetails.category?.name, link: tagDetails.category && categoryHref(tagDetails.category), }} oldEntity={{ name: oldTagDetails?.category?.name, link: oldTagDetails?.category && categoryHref(oldTagDetails.category), }} showDiff={showDiff} /> <AmendableListChangeRow name="Aliases" field="aliases" added={tagDetails.added_aliases?.map((a) => ({ value: a }))} removed={tagDetails.removed_aliases?.map((a) => ({ value: a }))} renderItem={(o) => <>{o.value}</>} getKey={(o) => o.value} showDiff={showDiff} /> </> ); const renderAmendablePerformerDetails = ( performerDetails: PerformerDetails, oldPerformerDetails: OldPerformerDetails | undefined, showDiff: boolean, setModifyAliases: boolean, ) => ( <> {performerDetails.name && ( <AmendableChangeRow name="Name" field="name" newValue={performerDetails.name} oldValue={oldPerformerDetails?.name} showDiff={showDiff} /> )} {oldPerformerDetails?.name && performerDetails.name !== oldPerformerDetails.name && ( <div className="d-flex mb-2 align-items-center"> <Icon icon={setModifyAliases ? faCheck : faXmark} color={setModifyAliases ? "green" : "red"} className="ms-auto" /> <span className="ms-2">Set performance aliases to old name</span> </div> )} <AmendableChangeRow name="Disambiguation" field="disambiguation" newValue={performerDetails.disambiguation} oldValue={oldPerformerDetails?.disambiguation} showDiff={showDiff} /> <AmendableListChangeRow name="Aliases" field="aliases" added={performerDetails.added_aliases?.map((a) => ({ value: a }))} removed={performerDetails.removed_aliases?.map((a) => ({ value: a }))} renderItem={(o) => <>{o.value}</>} getKey={(o) => o.value} showDiff={showDiff} /> <AmendableChangeRow name="Gender" field="gender" newValue={ performerDetails.gender && GenderTypes[performerDetails.gender as keyof typeof GenderEnum] } oldValue={ oldPerformerDetails?.gender && GenderTypes[oldPerformerDetails.gender as keyof typeof GenderEnum] } showDiff={showDiff} /> <AmendableChangeRow name="Birthdate" field="birthdate" newValue={performerDetails.birthdate} oldValue={oldPerformerDetails?.birthdate} showDiff={showDiff} /> <AmendableChangeRow name="Deathdate" field="deathdate" newValue={performerDetails.deathdate} oldValue={oldPerformerDetails?.deathdate} showDiff={showDiff} /> <AmendableChangeRow name="Eye Color" field="eye_color" newValue={ performerDetails.eye_color && EyeColorTypes[performerDetails.eye_color as keyof typeof EyeColorEnum] } oldValue={ oldPerformerDetails?.eye_color && EyeColorTypes[ oldPerformerDetails.eye_color as keyof typeof EyeColorEnum ] } showDiff={showDiff} /> <AmendableChangeRow name="Hair Color" field="hair_color" newValue={ performerDetails.hair_color && HairColorTypes[ performerDetails.hair_color as keyof typeof HairColorEnum ] } oldValue={ oldPerformerDetails?.hair_color && HairColorTypes[ oldPerformerDetails.hair_color as keyof typeof HairColorEnum ] } showDiff={showDiff} /> <AmendableChangeRow name="Height" field="height" newValue={performerDetails.height} oldValue={oldPerformerDetails?.height} showDiff={showDiff} /> <AmendableChangeRow name="Breast Type" field="breast_type" newValue={ performerDetails.breast_type && BreastTypes[performerDetails.breast_type as keyof typeof BreastTypeEnum] } oldValue={ oldPerformerDetails?.breast_type && BreastTypes[ oldPerformerDetails.breast_type as keyof typeof BreastTypeEnum ] } showDiff={showDiff} /> <AmendableBraSizeRow newBandSize={performerDetails.band_size} newCupSize={performerDetails.cup_size} oldBandSize={oldPerformerDetails?.band_size} oldCupSize={oldPerformerDetails?.cup_size} showDiff={showDiff} /> <AmendableChangeRow name="Waist Size" field="waist_size" newValue={performerDetails.waist_size} oldValue={oldPerformerDetails?.waist_size} showDiff={showDiff} /> <AmendableChangeRow name="Hip Size" field="hip_size" newValue={performerDetails.hip_size} oldValue={oldPerformerDetails?.hip_size} showDiff={showDiff} /> <AmendableChangeRow name="Nationality" field="country" newValue={getCountryByISO(performerDetails.country)} oldValue={getCountryByISO(oldPerformerDetails?.country)} showDiff={showDiff} /> <AmendableChangeRow name="Ethnicity" field="ethnicity" newValue={ performerDetails.ethnicity && EthnicityTypes[performerDetails.ethnicity as keyof typeof EthnicityEnum] } oldValue={ oldPerformerDetails?.ethnicity && EthnicityTypes[ oldPerformerDetails.ethnicity as keyof typeof EthnicityEnum ] } showDiff={showDiff} /> <AmendableChangeRow name="Career Start" field="career_start_year" newValue={performerDetails.career_start_year} oldValue={oldPerformerDetails?.career_start_year} showDiff={showDiff} /> <AmendableChangeRow name="Career End" field="career_end_year" newValue={performerDetails.career_end_year} oldValue={oldPerformerDetails?.career_end_year} showDiff={showDiff} /> <AmendableListChangeRow name="Tattoos" field="tattoos" added={performerDetails.added_tattoos} removed={performerDetails.removed_tattoos} renderItem={(o) => <>{formatBodyModification(o)}</>} getKey={(o) => `${o.location}-${o.description ?? ""}`} showDiff={showDiff} /> <AmendableListChangeRow name="Piercings" field="piercings" added={performerDetails.added_piercings} removed={performerDetails.removed_piercings} renderItem={(o) => <>{formatBodyModification(o)}</>} getKey={(o) => `${o.location}-${o.description ?? ""}`} showDiff={showDiff} /> <AmendableURLChangeRow field="urls" newURLs={performerDetails.added_urls} oldURLs={performerDetails.removed_urls} showDiff={showDiff} /> <AmendableImageChangeRow field="images" newImages={performerDetails.added_images} oldImages={performerDetails.removed_images} showDiff={showDiff} /> {performerDetails.draft_id && ( <Row className="mb-2"> <Col xs={{ offset: 2 }}> <h6> <Icon icon={faEdit} color="green" /> <span className="ms-1">Submitted by draft</span> </h6> </Col> </Row> )} </> ); const renderAmendableSceneDetails = ( sceneDetails: SceneDetails, oldSceneDetails: OldSceneDetails | undefined, showDiff: boolean, ) => ( <> {sceneDetails.title && ( <AmendableChangeRow name="Title" field="title" newValue={sceneDetails.title} oldValue={oldSceneDetails?.title} showDiff={showDiff} /> )} <AmendableChangeRow name="Date" field="date" newValue={sceneDetails.date} oldValue={oldSceneDetails?.date} showDiff={showDiff} /> <AmendableChangeRow name="Duration" field="duration" newValue={formatDuration(sceneDetails.duration)} oldValue={formatDuration(oldSceneDetails?.duration)} showDiff={showDiff} /> <AmendableListChangeRow name="Performers" field="performers" added={sceneDetails.added_performers} removed={sceneDetails.removed_performers} renderItem={renderPerformer} getKey={(o) => o.performer.id} showDiff={showDiff} /> <AmendableLinkedChangeRow name="Studio" field="studio_id" newEntity={{ name: sceneDetails.studio?.name, link: sceneDetails.studio && studioHref(sceneDetails.studio), }} oldEntity={{ name: oldSceneDetails?.studio?.name, link: oldSceneDetails?.studio && studioHref(oldSceneDetails.studio), }} showDiff={showDiff} /> <AmendableURLChangeRow field="urls" newURLs={sceneDetails.added_urls} oldURLs={sceneDetails.removed_urls} showDiff={showDiff} /> <AmendableChangeRow name="Details" field="details" newValue={sceneDetails.details} oldValue={oldSceneDetails?.details} showDiff={showDiff} /> <AmendableChangeRow name="Director" field="director" newValue={sceneDetails.director} oldValue={oldSceneDetails?.director} showDiff={showDiff} /> <AmendableChangeRow name="Production Date" field="production_date" newValue={sceneDetails.production_date} oldValue={oldSceneDetails?.production_date} showDiff={showDiff} /> <AmendableChangeRow name="Studio Code" field="code" newValue={sceneDetails.code} oldValue={oldSceneDetails?.code} showDiff={showDiff} /> <AmendableListChangeRow name="Tags" field="tags" added={sceneDetails.added_tags?.slice().sort(compareByName)} removed={sceneDetails.removed_tags?.slice().sort(compareByName)} renderItem={renderTag} getKey={(o) => o.id} showDiff={showDiff} /> <AmendableImageChangeRow field="images" newImages={sceneDetails?.added_images} oldImages={sceneDetails?.removed_images} showDiff={showDiff} /> <AmendableListChangeRow name="Fingerprints" field="fingerprints" added={sceneDetails.added_fingerprints} removed={sceneDetails.removed_fingerprints} renderItem={renderFingerprint} getKey={(o) => `${o.hash}${o.algorithm}`} showDiff={showDiff} /> {sceneDetails.draft_id && ( <Row className="mb-2"> <Col xs={{ offset: 2 }}> <h6> <Icon icon={faEdit} color="green" /> <span className="ms-1">Submitted by draft</span> </h6> </Col> </Row> )} </> ); const renderAmendableStudioDetails = ( studioDetails: StudioDetails, oldStudioDetails: OldStudioDetails | undefined, showDiff: boolean, ) => ( <> <AmendableChangeRow name="Name" field="name" newValue={studioDetails.name} oldValue={oldStudioDetails?.name} showDiff={showDiff} /> <AmendableListChangeRow name="Aliases" field="aliases" added={studioDetails.added_aliases?.map((a) => ({ value: a }))} removed={studioDetails.removed_aliases?.map((a) => ({ value: a }))} renderItem={(o) => <>{o.value}</>} getKey={(o) => o.value} showDiff={showDiff} /> <AmendableLinkedChangeRow name="Network" field="parent_id" newEntity={{ name: studioDetails.parent?.name, link: studioDetails.parent && studioHref(studioDetails.parent), }} oldEntity={{ name: oldStudioDetails?.parent?.name, link: oldStudioDetails?.parent && studioHref(oldStudioDetails.parent), }} showDiff={showDiff} /> <AmendableURLChangeRow field="urls" newURLs={studioDetails.added_urls} oldURLs={studioDetails.removed_urls} showDiff={showDiff} /> <AmendableImageChangeRow field="images" newImages={studioDetails.added_images} oldImages={studioDetails.removed_images} showDiff={showDiff} /> </> ); interface AmendableModifyEditProps { details: Details | null; oldDetails?: OldDetails | null; options?: Options; } const AmendableModifyEdit: FC<AmendableModifyEditProps> = ({ details, oldDetails, options, }) => { if (!details) return null; const showDiff = !!oldDetails; if (isTagEdit(details) && (isTagEdit(oldDetails) || !oldDetails)) { return renderAmendableTagDetails( details, oldDetails ?? undefined, showDiff, ); } if ( isPerformerEdit(details) && (isPerformerEdit(oldDetails) || !oldDetails) ) { return renderAmendablePerformerDetails( details, oldDetails ?? undefined, showDiff, options?.set_modify_aliases ?? false, ); } if (isStudioEdit(details) && (isStudioEdit(oldDetails) || !oldDetails)) { return renderAmendableStudioDetails( details, oldDetails ?? undefined, showDiff, ); } if (isSceneEdit(details) && (isSceneEdit(oldDetails) || !oldDetails)) { return renderAmendableSceneDetails( details, oldDetails ?? undefined, showDiff, ); } return null; }; export default AmendableModifyEdit; ================================================ FILE: frontend/src/components/amendableEditCard/AmendableURLChangeRow.tsx ================================================ import type { FC } from "react"; import { Col, Row, Button } from "react-bootstrap"; import { faXmark, faUndo } from "@fortawesome/free-solid-svg-icons"; import cx from "classnames"; import { SiteLink, Icon } from "src/components/fragments"; import type { URL } from "src/components/urlChangeRow"; import { useAmendment } from "./AmendmentContext"; const CLASSNAME = "URLChangeRow"; interface AmendableURLChangeRowProps { field: string; newURLs?: URL[] | null; oldURLs?: URL[] | null; showDiff?: boolean; } const AmendableURLChangeRow: FC<AmendableURLChangeRowProps> = ({ field, newURLs, oldURLs, showDiff, }) => { const { state, clearAddedItem, clearRemovedItem, restoreAddedItem, restoreRemovedItem, } = useAmendment(); const removedAddedIndices = state.removedAddedItems.get(field); const removedRemovedIndices = state.removedRemovedItems.get(field); if ((newURLs ?? []).length === 0 && (oldURLs ?? []).length === 0) return null; return ( <Row className={CLASSNAME}> <b className="col-2 text-end">Links</b> {showDiff && ( <Col xs={4}> {(oldURLs ?? []).length > 0 && ( <> <h6>Removed</h6> <div className={CLASSNAME}> <ul className="ps-0"> {(oldURLs ?? []).map((url, index) => { const isRemoved = removedRemovedIndices?.has(index); return ( <li key={url.url} className={cx("d-flex align-items-start", { "opacity-50 text-decoration-line-through": isRemoved, })} > <SiteLink site={url.site} /> <a href={url.url} target="_blank" rel="noopener noreferrer" className="d-inline-block flex-grow-1 text-break" > {url.url} </a> {!isRemoved && ( <Button variant="danger" size="sm" className="ms-2" onClick={() => clearRemovedItem(field, index)} title="Remove this URL change from the edit" > <Icon icon={faXmark} /> </Button> )} {isRemoved && ( <Button variant="secondary" size="sm" className="ms-2" onClick={() => restoreRemovedItem(field, index)} title="Restore this URL" > <Icon icon={faUndo} /> </Button> )} </li> ); })} </ul> </div> </> )} </Col> )} <Col xs={showDiff ? 4 : 8}> {(newURLs ?? []).length > 0 && ( <> {showDiff && <h6>Added</h6>} <div className={CLASSNAME}> <ul className="ps-0"> {(newURLs ?? []).map((url, index) => { const isRemoved = removedAddedIndices?.has(index); return ( <li key={url.url} className={cx("d-flex align-items-start", { "opacity-50 text-decoration-line-through": isRemoved, })} > <SiteLink site={url.site} /> <a href={url.url} target="_blank" rel="noopener noreferrer" className="d-inline-block flex-grow-1 text-break" > {url.url} </a> {!isRemoved && ( <Button variant="danger" size="sm" className="ms-2" onClick={() => clearAddedItem(field, index)} title="Remove this URL from the edit" > <Icon icon={faXmark} /> </Button> )} {isRemoved && ( <Button variant="secondary" size="sm" className="ms-2" onClick={() => restoreAddedItem(field, index)} title="Restore this URL" > <Icon icon={faUndo} /> </Button> )} </li> ); })} </ul> </div> </> )} </Col> <Col xs={2} /> </Row> ); }; export default AmendableURLChangeRow; ================================================ FILE: frontend/src/components/amendableEditCard/AmendmentContext.tsx ================================================ import { createContext, useContext, useState, useCallback, type FC, type ReactNode, } from "react"; export interface AmendmentState { removedFields: Set<string>; removedAddedItems: Map<string, Set<number>>; removedRemovedItems: Map<string, Set<number>>; } interface AmendmentContextValue { state: AmendmentState; clearField: (field: string) => void; clearAddedItem: (field: string, index: number) => void; clearRemovedItem: (field: string, index: number) => void; restoreField: (field: string) => void; restoreAddedItem: (field: string, index: number) => void; restoreRemovedItem: (field: string, index: number) => void; hasChanges: boolean; } const AmendmentContext = createContext<AmendmentContextValue | null>(null); export const useAmendment = () => { const context = useContext(AmendmentContext); if (!context) { throw new Error("useAmendment must be used within AmendmentProvider"); } return context; }; export const useAmendmentOptional = () => useContext(AmendmentContext); interface AmendmentProviderProps { children: ReactNode; } export const AmendmentProvider: FC<AmendmentProviderProps> = ({ children }) => { const [removedFields, setRemovedFields] = useState<Set<string>>(new Set()); const [removedAddedItems, setRemovedAddedItems] = useState< Map<string, Set<number>> >(new Map()); const [removedRemovedItems, setRemovedRemovedItems] = useState< Map<string, Set<number>> >(new Map()); const clearField = useCallback((field: string) => { setRemovedFields((prev) => { const next = new Set(prev); next.add(field); return next; }); }, []); const clearAddedItem = useCallback((field: string, index: number) => { setRemovedAddedItems((prev) => { const next = new Map(prev); const indices = next.get(field) ?? new Set<number>(); indices.add(index); next.set(field, indices); return next; }); }, []); const clearRemovedItem = useCallback((field: string, index: number) => { setRemovedRemovedItems((prev) => { const next = new Map(prev); const indices = next.get(field) ?? new Set<number>(); indices.add(index); next.set(field, indices); return next; }); }, []); const restoreField = useCallback((field: string) => { setRemovedFields((prev) => { const next = new Set(prev); next.delete(field); return next; }); }, []); const restoreAddedItem = useCallback((field: string, index: number) => { setRemovedAddedItems((prev) => { const next = new Map(prev); const indices = next.get(field); if (indices) { indices.delete(index); if (indices.size === 0) { next.delete(field); } else { next.set(field, indices); } } return next; }); }, []); const restoreRemovedItem = useCallback((field: string, index: number) => { setRemovedRemovedItems((prev) => { const next = new Map(prev); const indices = next.get(field); if (indices) { indices.delete(index); if (indices.size === 0) { next.delete(field); } else { next.set(field, indices); } } return next; }); }, []); const hasChanges = removedFields.size > 0 || Array.from(removedAddedItems.values()).some((s) => s.size > 0) || Array.from(removedRemovedItems.values()).some((s) => s.size > 0); const value: AmendmentContextValue = { state: { removedFields, removedAddedItems, removedRemovedItems, }, clearField, clearAddedItem, clearRemovedItem, restoreField, restoreAddedItem, restoreRemovedItem, hasChanges, }; return ( <AmendmentContext.Provider value={value}> {children} </AmendmentContext.Provider> ); }; ================================================ FILE: frontend/src/components/amendableEditCard/index.ts ================================================ export { default as AmendableModifyEdit } from "./AmendableModifyEdit"; export { default as AmendableChangeRow } from "./AmendableChangeRow"; export { default as AmendableListChangeRow } from "./AmendableListChangeRow"; export { default as AmendableURLChangeRow } from "./AmendableURLChangeRow"; export { default as AmendableImageChangeRow } from "./AmendableImageChangeRow"; export { default as AmendableLinkedChangeRow } from "./AmendableLinkedChangeRow"; export { AmendmentProvider, useAmendment, type AmendmentState, } from "./AmendmentContext"; ================================================ FILE: frontend/src/components/changeRow/ChangeRow.tsx ================================================ import type { FC } from "react"; import { Col, Row } from "react-bootstrap"; import cx from "classnames"; export interface ChangeRowProps { name?: string; newValue?: string | number | null; oldValue?: string | number | null; showDiff?: boolean; } const ChangeRow: FC<ChangeRowProps> = ({ name, newValue, oldValue, showDiff = false, }) => name && (newValue || oldValue) ? ( <Row className="mb-2"> <b className="col-2 text-end pt-1">{name}</b> {showDiff && ( <Col xs={5}> <div className="EditDiff bg-danger">{oldValue}</div> </Col> )} <Col xs={showDiff ? 5 : 10}> <div className={cx("EditDiff", { "bg-success": showDiff })}> {newValue} </div> </Col> </Row> ) : null; export default ChangeRow; ================================================ FILE: frontend/src/components/changeRow/index.ts ================================================ export { default } from "./ChangeRow"; ================================================ FILE: frontend/src/components/checkboxSelect/CheckboxSelect.tsx ================================================ // biome-ignore-all lint/correctness/noNestedComponentDefinitions: Necessary for react-select import type { FC } from "react"; import Select, { type OnChangeValue } from "react-select"; import { Form } from "react-bootstrap"; import { uniq } from "lodash-es"; interface MultiSelectProps { values: IOptionType[]; onChange: (values: string[]) => void; placeholder?: string; plural?: string; selected?: string[]; } interface IOptionType { label: string; value: string; subValues: string[] | null; } const CheckboxSelect: FC<MultiSelectProps> = ({ values, onChange, placeholder = "Select...", plural = "values", selected = [], }) => { const handleChange = (vals: OnChangeValue<IOptionType, true>) => { onChange(uniq(vals.flatMap((v) => [v.value, ...(v.subValues ?? [])]))); }; const formatLabel = ( option: IOptionType, meta: { context: "menu" | "value" }, ) => { if (meta.context === "menu") return option.subValues === null ? ( <div className="d-flex ms-3"> <Form.Check className="me-2" checked={selected.includes(option.value)} /> {option.label} </div> ) : ( <div className="d-flex"> <Form.Check className="me-2" checked={selected.includes(option.value)} /> <span className="text-muted">{option.label}</span> </div> ); return `${ selected.length === 0 ? "All" : selected.length } ${plural} selected`; }; const selectedOptions = values.filter((val) => selected.includes(val.value)); return ( <Select value={selectedOptions} isMulti classNamePrefix="react-select" className="react-select CheckboxSelect" options={values} onChange={handleChange} formatOptionLabel={formatLabel} hideSelectedOptions={false} closeMenuOnSelect={false} placeholder={placeholder} noOptionsMessage={() => null} styles={{ option: (base) => ({ ...base, backgroundColor: "transparent", }), }} components={{ DropdownIndicator: () => null, IndicatorSeparator: () => null, MultiValue: (e) => e.data.value === selected[0] ? ( <span className="text-secondary"> {selected.length} {plural} selected </span> ) : null, }} /> ); }; export default CheckboxSelect; ================================================ FILE: frontend/src/components/checkboxSelect/index.ts ================================================ import CheckboxSelect from "./CheckboxSelect"; export default CheckboxSelect; ================================================ FILE: frontend/src/components/checkboxSelect/styles.scss ================================================ .CheckboxSelect { width: 20rem; } ================================================ FILE: frontend/src/components/deleteButton/DeleteButton.tsx ================================================ import { type FC, useState } from "react"; import { Button } from "react-bootstrap"; import Modal from "src/components/modal"; import { useCurrentUser } from "src/hooks"; interface DeleteButtonProps { message?: string; onClick: () => void; disabled?: boolean; className?: string; } const DeleteButton: FC<DeleteButtonProps> = ({ message, onClick, disabled = false, className, }) => { const { isAdmin } = useCurrentUser(); const [showDelete, setShowDelete] = useState(false); const toggleModal = () => setShowDelete(true); const handleDelete = (status: boolean): void => { if (status) onClick(); setShowDelete(false); }; const deleteModal = showDelete && ( <Modal message={ message ?? `Are you sure you want to delete this? This operation cannot be undone.` } callback={handleDelete} /> ); return ( <> {deleteModal} {isAdmin && ( <Button variant="danger" disabled={showDelete || disabled} onClick={toggleModal} className={className} > Delete </Button> )} </> ); }; export default DeleteButton; ================================================ FILE: frontend/src/components/deleteButton/index.ts ================================================ import DeleteButton from "./DeleteButton"; export default DeleteButton; ================================================ FILE: frontend/src/components/editCard/AddComment.tsx ================================================ import { type FC, useState } from "react"; import { Button, Form } from "react-bootstrap"; import { useEditComment } from "src/graphql"; import cx from "classnames"; import { NoteInput } from "src/components/form"; import { useCurrentUser } from "src/hooks"; import { CombinedGraphQLErrors } from "@apollo/client"; interface IProps { editID: string; } const AddComment: FC<IProps> = ({ editID }) => { const { isEditor } = useCurrentUser(); const [showInput, setShowInput] = useState(false); const [error, setError] = useState<string>(); const [comment, setComment] = useState(""); const [saveComment, { loading: saving }] = useEditComment(); if (!showInput) return ( <div className="d-flex"> {!showInput && isEditor && ( <Button className="ms-auto minimal" variant="link" onClick={() => setShowInput(true)} > Add Comment </Button> )} </div> ); const handleSaveComment = async () => { const text = comment.trim(); if (text) { const res = await saveComment({ variables: { input: { id: editID, comment: text } }, }); if (CombinedGraphQLErrors.is(res.error)) { setError(res.error.message); } else { setShowInput(false); setError(""); } } }; return ( <Form.Group className="mb-3"> <NoteInput className={cx({ "is-invalid": error })} onChange={(text) => setComment(text)} /> <Form.Control.Feedback type="invalid" className="text-end"> {error} </Form.Control.Feedback> <div className="d-flex mt-2"> <Button variant="secondary" className="ms-auto" onClick={() => setShowInput(false)} > Cancel </Button> <Button variant="primary" className="ms-2" disabled={saving || !comment.trim()} onClick={handleSaveComment} > Save </Button> </div> </Form.Group> ); }; export default AddComment; ================================================ FILE: frontend/src/components/editCard/EditCard.tsx ================================================ import type { FC } from "react"; import { Card, Col, Row } from "react-bootstrap"; import { Link } from "react-router-dom"; import cx from "classnames"; import { faRobot } from "@fortawesome/free-solid-svg-icons"; import { Icon, Tooltip } from "src/components/fragments"; import { OperationEnum, type EditFragment } from "src/graphql"; import { formatDateTime, editHref, userHref, formatOrdinals } from "src/utils"; import ModifyEdit from "./ModifyEdit"; import EditComment from "./EditComment"; import EditHeader from "./EditHeader"; import AddComment from "./AddComment"; import VoteBar from "./VoteBar"; import EditExpiration from "./EditExpiration"; import EditStatus from "./EditStatus"; import Votes from "./Votes"; const CLASSNAME = "EditCard"; interface Props { edit: EditFragment; showVotes?: boolean; showVoteBar?: boolean; hideDiff?: boolean; } const EditCardComponent: FC<Props> = ({ edit, showVotes = false, showVoteBar = true, hideDiff = false, }) => { const title = `${edit.operation.toLowerCase()} ${edit.target_type.toLowerCase()}`; const created = new Date(edit.created); const creation = edit.operation === OperationEnum.CREATE && ( <ModifyEdit details={edit.details} /> ); const modifications = edit.operation !== OperationEnum.CREATE && ( <ModifyEdit details={edit.details} oldDetails={edit.old_details} options={edit.options ?? undefined} /> ); const comments = (edit.comments ?? []).map((comment) => ( <EditComment {...comment} key={comment.id} /> )); return ( <Card className={cx(CLASSNAME, "mb-3")}> <Card.Header className="row"> <div className="flex-column col-4"> <Link to={editHref(edit)}> <h5 className="text-capitalize">{title.toLowerCase()}</h5> </Link> <div> <b className="me-2">Author:</b> {edit.user ? ( <Link to={userHref(edit.user)}> <span>{edit.user.name}</span> </Link> ) : ( <span>Deleted User</span> )} {edit.bot && ( <Tooltip text="Edit submitted by an automated script" delay={50} placement="auto" > <span> <Icon icon={faRobot} className="ms-2" /> </span> </Tooltip> )} </div> <div> <b className="me-2">Created:</b> <span>{formatDateTime(created)}</span> </div> {edit.updated && edit.update_count > 0 && ( <div> <b className="me-2">Updated:</b> <span>{formatDateTime(edit.updated)}</span> <small className="text-muted align-text-top ms-2">{`${formatOrdinals(edit.update_count)} revision`}</small> </div> )} </div> <div className="flex-column col-4 ms-auto text-end"> <div> <b className="me-2">Status:</b> <EditStatus {...edit} /> <EditExpiration edit={edit} /> {showVoteBar && <VoteBar edit={edit} />} </div> </div> </Card.Header> <hr /> <Card.Body> <EditHeader edit={edit} compact={hideDiff} /> {!hideDiff ? ( <> {creation} {modifications} <Row className="mt-2"> <Col md={{ offset: 4, span: 8 }}> {showVotes && <Votes edit={edit} />} {comments} <AddComment editID={edit.id} /> </Col> </Row> </> ) : ( showVotes && <Votes edit={edit} /> )} </Card.Body> </Card> ); }; export default EditCardComponent; ================================================ FILE: frontend/src/components/editCard/EditComment.tsx ================================================ import type { FC } from "react"; import { Card } from "react-bootstrap"; import { Link } from "react-router-dom"; import { formatDateTime, userHref, Markdown } from "src/utils"; const CLASSNAME = "EditComment"; interface Props { id: string; comment: string; date: string; user?: { name: string; id: string } | null; } const EditComment: FC<Props> = ({ id, comment, date, user }) => ( <Card className={CLASSNAME}> <Card.Body className="pb-0"> <Markdown text={comment} unique={id} /> </Card.Body> <Card.Footer className="text-end"> {user ? ( <Link to={userHref(user)}>{user.name}</Link> ) : ( <span>Deleted User</span> )} <span className="mx-1">•</span> <span>{formatDateTime(date, false)}</span> </Card.Footer> </Card> ); export default EditComment; ================================================ FILE: frontend/src/components/editCard/EditExpiration.tsx ================================================ import type { FC } from "react"; import type { Temporal } from "temporal-polyfill"; import { formatDistance, parseInstant, isInstantInFuture, formatInstant, } from "src/utils"; import { Tooltip } from "src/components/fragments"; import { useConfig, VoteStatusEnum, type EditFragment } from "src/graphql"; interface Props { edit: EditFragment; } const TooltipMessage: FC<{ pass: boolean; time: Temporal.Instant | undefined; }> = ({ pass, time }) => ( <span> If no other votes are cast the edit will{" "} <b className={pass ? "text-success" : "text-danger"}> {pass ? "pass" : "fail"} </b>{" "} at {time ? formatInstant(time) : ""} </span> ); const ExpirationNotification: FC<Props> = ({ edit }) => { const { data } = useConfig(); const config = data?.getConfig; if ( !config?.vote_cron_interval || edit.status !== VoteStatusEnum.PENDING || !edit.expires ) return null; // Pending edits that have reached the voting threshold have shorter voting periods. // This will happen for destructive edits, or when votes are not unanimous. const shortVotingPeriod = config.vote_application_threshold > 0 && edit.vote_count >= config.vote_application_threshold; const expirationTime = parseInstant(edit.expires); const expirationDistance = expirationTime && isInstantInFuture(expirationTime) ? formatDistance(expirationTime) : "in a moment"; const threshold = edit.destructive ? 1 : 0; const pass = shortVotingPeriod || edit.vote_count >= threshold; return ( <div> <Tooltip delay={0} text={<TooltipMessage pass={pass} time={expirationTime} />} > <span> Voting closes{" "} <b> <u>{expirationDistance}</u> </b> </span> </Tooltip> </div> ); }; export default ExpirationNotification; ================================================ FILE: frontend/src/components/editCard/EditHeader.tsx ================================================ import { type FC, useMemo } from "react"; import { Link } from "react-router-dom"; import { Col, Row } from "react-bootstrap"; import { faCheck, faXmark, faVideo } from "@fortawesome/free-solid-svg-icons"; import { OperationEnum, type EditFragment } from "src/graphql"; import { getEditTargetRoute, isPerformer, isScene, isSceneEdit, performerHref, studioHref, getEditTargetName, } from "src/utils"; import { Icon } from "src/components/fragments"; type Target = NonNullable<EditFragment["target"]>; const renderTargetLink = (obj?: Target | null) => { if (!obj) return null; if (isPerformer(obj)) { return ( <Link to={performerHref(obj)}> {obj.name} {obj.disambiguation && ( <small className="text-muted ms-1">({obj.disambiguation})</small> )} </Link> ); } else { return <Link to={getEditTargetRoute(obj)}>{getEditTargetName(obj)}</Link>; } }; const renderTargetAddendum = (obj?: Target | null) => { if (isScene(obj) && obj?.studio) return ( <> <span className="mx-2">•</span> <Icon icon={faVideo} className="me-1" /> <Link to={studioHref(obj.studio)}>{obj.studio.name}</Link> </> ); return null; }; interface EditHeaderProps { edit: EditFragment; compact?: boolean; } const EditHeader: FC<EditHeaderProps> = ({ edit, compact = false }) => { const header = useMemo(() => { switch (edit.operation) { case OperationEnum.MODIFY: if (!edit.target) return null; return ( <> <Col xs={2} className="fw-bold text-end"> Modifying {edit.target_type.toLowerCase()} </Col> <Col> {renderTargetLink(edit.target)} {renderTargetAddendum(edit.target)} </Col> </> ); case OperationEnum.CREATE: if (edit.applied) { return ( <> <Col xs={2} className="fw-bold text-end"> Created {edit.target_type.toLowerCase()} </Col> <Col className="ps-3"> {renderTargetLink(edit.target)} {renderTargetAddendum(edit.target)} </Col> </> ); } // For unapplied CREATE edits, show scene info from details if available if (compact && isSceneEdit(edit.details) && edit.details.title) { return ( <> <Col xs={2} className="fw-bold text-end"> Creating {edit.target_type.toLowerCase()} </Col> <Col className="ps-3"> <span>{edit.details.title}</span> {edit.details.studio && ( <> <span className="mx-2">•</span> <Icon icon={faVideo} className="me-1" /> <Link to={studioHref(edit.details.studio)}> {edit.details.studio.name} </Link> </> )} </Col> </> ); } return null; case OperationEnum.MERGE: if (!edit.target) return null; return ( <Col className="lh-base"> <Row> <Col xs={2} className="fw-bold text-end"> Merge </Col> <Col xs={10}> {edit.merge_sources?.map((target) => ( <div key={target.id}> {renderTargetLink(target)} {renderTargetAddendum(edit.target)} </div> ))} </Col> </Row> <Row> <Col xs={2} className="fw-bold text-end"> Into </Col> <Col xs={10}> {renderTargetLink(edit.target)} {renderTargetAddendum(edit.target)} </Col> </Row> {isPerformer(edit.target) && ( <Row> <div className="offset-2 d-flex align-items-center"> <Icon icon={edit.options?.set_merge_aliases ? faCheck : faXmark} color={edit.options?.set_merge_aliases ? "green" : "red"} /> <span className="ms-1"> Set performance aliases to old name </span> </div> </Row> )} </Col> ); case OperationEnum.DESTROY: if (!edit.target) return null; return ( <> <Col xs={2} className="fw-bold text-end"> Deleting </Col> <Col> <span className="EditDiff bg-danger"> {renderTargetLink(edit.target)} </span> {renderTargetAddendum(edit.target)} </Col> </> ); } }, [edit, compact]); return header ? <Row className="mb-4">{header}</Row> : null; }; export default EditHeader; ================================================ FILE: frontend/src/components/editCard/EditStatus.tsx ================================================ import type { FC } from "react"; import { Badge, type BadgeProps } from "react-bootstrap"; import { VoteStatusEnum } from "src/graphql"; import { EditStatusTypes } from "src/constants/enums"; import { Tooltip } from "src/components/fragments"; import { formatDateTime } from "src/utils"; interface Props { status: VoteStatusEnum; closed?: string | null; } const EditStatus: FC<Props> = ({ closed, status }) => { let editVariant: BadgeProps["bg"] = "warning"; if ( status === VoteStatusEnum.REJECTED || status === VoteStatusEnum.IMMEDIATE_REJECTED || status === VoteStatusEnum.FAILED || status === VoteStatusEnum.CANCELED ) editVariant = "danger"; else if ( status === VoteStatusEnum.ACCEPTED || status === VoteStatusEnum.IMMEDIATE_ACCEPTED ) editVariant = "success"; let tooltip = ""; switch (status) { case VoteStatusEnum.REJECTED: tooltip = "Edit did not get sufficient votes to pass."; break; case VoteStatusEnum.CANCELED: tooltip = "Edit was cancelled by the editor."; break; case VoteStatusEnum.IMMEDIATE_REJECTED: tooltip = "Edit was cancelled by an admin."; break; case VoteStatusEnum.FAILED: tooltip = "Edit application failed due to an error. See edit note for more details."; break; } const tooltipContent = closed || tooltip ? ( <> {closed && ( <div> Closed <b>{formatDateTime(closed)}</b> </div> )} {tooltip} </> ) : ( "" ); return ( <Tooltip text={tooltipContent}> <Badge className="text-uppercase" bg={editVariant}> {EditStatusTypes[status]} </Badge> </Tooltip> ); }; export default EditStatus; ================================================ FILE: frontend/src/components/editCard/ModifyEdit.tsx ================================================ import type { FC } from "react"; import { Col, Row } from "react-bootstrap"; import { faCheck, faXmark, faEdit } from "@fortawesome/free-solid-svg-icons"; import type { FingerprintAlgorithm, PerformerFragment, GenderEnum, EthnicityEnum, BreastTypeEnum, EditFragment, HairColorEnum, EyeColorEnum, } from "src/graphql"; import { formatDuration, getCountryByISO, isTagEdit, isPerformerEdit, formatBodyModification, isStudioEdit, isSceneEdit, studioHref, categoryHref, compareByName, } from "src/utils"; import { EthnicityTypes, HairColorTypes, EyeColorTypes, BreastTypes, GenderTypes, } from "src/constants"; import { Icon } from "src/components/fragments"; import ChangeRow from "src/components/changeRow"; import ImageChangeRow from "src/components/imageChangeRow"; import URLChangeRow, { type URL } from "src/components/urlChangeRow"; import LinkedChangeRow from "../linkedChangeRow"; import ListChangeRow from "../listChangeRow"; import { renderPerformer, renderTag, renderFingerprint } from "./renderEntity"; type Details = EditFragment["details"]; type OldDetails = EditFragment["old_details"]; type Options = EditFragment["options"]; export type Image = { height: number; id: string; url: string; width: number; }; // eslint-disable-next-line @typescript-eslint/no-unused-vars type StartingWith<T, K extends string> = T extends `${K}${infer _}` ? T : never; export type TargetOldDetails<T> = Omit< T, StartingWith<keyof T, "added_" | "removed_"> | "draft_id" >; export interface TagDetails { name?: string | null; description?: string | null; category?: { id: string; name: string } | null; added_aliases?: string[] | null; removed_aliases?: string[] | null; } export type OldTagDetails = TargetOldDetails<TagDetails>; export const renderTagDetails = ( tagDetails: TagDetails, oldTagDetails: OldTagDetails | undefined, showDiff: boolean, ) => ( <> <ChangeRow name="Name" newValue={tagDetails.name} oldValue={oldTagDetails?.name} showDiff={showDiff} /> <ChangeRow name="Description" newValue={tagDetails.description} oldValue={oldTagDetails?.description} showDiff={showDiff} /> <LinkedChangeRow name="Category" newEntity={{ name: tagDetails.category?.name, link: tagDetails.category && categoryHref(tagDetails.category), }} oldEntity={{ name: oldTagDetails?.category?.name, link: oldTagDetails?.category && categoryHref(oldTagDetails.category), }} showDiff={showDiff} /> <ChangeRow name="Aliases" newValue={tagDetails.added_aliases?.join(", ")} oldValue={tagDetails.removed_aliases?.join(", ")} showDiff={showDiff} /> </> ); export type BodyMod = { location: string; description?: string | null; }; export interface PerformerDetails { name?: string | null; gender?: GenderEnum | null; disambiguation?: string | null; birthdate?: string | null; deathdate?: string | null; career_start_year?: number | null; career_end_year?: number | null; height?: number | null; band_size?: number | null; cup_size?: string | null; waist_size?: number | null; hip_size?: number | null; breast_type?: BreastTypeEnum | null; country?: string | null; ethnicity?: EthnicityEnum | null; eye_color?: string | null; hair_color?: string | null; added_tattoos?: BodyMod[] | null; removed_tattoos?: BodyMod[] | null; added_piercings?: BodyMod[] | null; removed_piercings?: BodyMod[] | null; added_aliases?: string[] | null; removed_aliases?: string[] | null; added_images?: (Image | null)[] | null; removed_images?: (Image | null)[] | null; added_urls?: URL[] | null; removed_urls?: URL[] | null; draft_id?: string | null; } export type OldPerformerDetails = TargetOldDetails<PerformerDetails>; export const renderPerformerDetails = ( performerDetails: PerformerDetails, oldPerformerDetails: OldPerformerDetails | undefined, showDiff: boolean, setModifyAliases = false, ) => ( <> {performerDetails.name && ( <ChangeRow name="Name" newValue={performerDetails.name} oldValue={oldPerformerDetails?.name} showDiff={showDiff} /> )} {oldPerformerDetails?.name && performerDetails.name !== oldPerformerDetails.name && ( <div className="d-flex mb-2 align-items-center"> <Icon icon={setModifyAliases ? faCheck : faXmark} color={setModifyAliases ? "green" : "red"} className="ms-auto" /> <span className="ms-2">Set performance aliases to old name</span> </div> )} <ChangeRow name="Disambiguation" newValue={performerDetails.disambiguation} oldValue={oldPerformerDetails?.disambiguation} showDiff={showDiff} /> <ChangeRow name="Aliases" newValue={performerDetails.added_aliases?.join(", ")} oldValue={performerDetails.removed_aliases?.join(", ")} showDiff={showDiff} /> <ChangeRow name="Gender" newValue={ performerDetails.gender && GenderTypes[performerDetails.gender as keyof typeof GenderEnum] } oldValue={ oldPerformerDetails?.gender && GenderTypes[oldPerformerDetails.gender as keyof typeof GenderEnum] } showDiff={showDiff} /> <ChangeRow name="Birthdate" newValue={performerDetails.birthdate} oldValue={oldPerformerDetails?.birthdate} showDiff={showDiff} /> <ChangeRow name="Deathdate" newValue={performerDetails.deathdate} oldValue={oldPerformerDetails?.deathdate} showDiff={showDiff} /> <ChangeRow name="Eye Color" newValue={ performerDetails.eye_color && EyeColorTypes[performerDetails.eye_color as keyof typeof EyeColorEnum] } oldValue={ oldPerformerDetails?.eye_color && EyeColorTypes[ oldPerformerDetails.eye_color as keyof typeof EyeColorEnum ] } showDiff={showDiff} /> <ChangeRow name="Hair Color" newValue={ performerDetails.hair_color && HairColorTypes[ performerDetails.hair_color as keyof typeof HairColorEnum ] } oldValue={ oldPerformerDetails?.hair_color && HairColorTypes[ oldPerformerDetails.hair_color as keyof typeof HairColorEnum ] } showDiff={showDiff} /> <ChangeRow name="Height" newValue={performerDetails.height} oldValue={oldPerformerDetails?.height} showDiff={showDiff} /> <ChangeRow name="Breast Type" newValue={ performerDetails.breast_type && BreastTypes[performerDetails.breast_type as keyof typeof BreastTypeEnum] } oldValue={ oldPerformerDetails?.breast_type && BreastTypes[ oldPerformerDetails.breast_type as keyof typeof BreastTypeEnum ] } showDiff={showDiff} /> <ChangeRow name="Bra Size" newValue={`${performerDetails.band_size || ""}${ performerDetails.cup_size ?? "" }`} oldValue={`${oldPerformerDetails?.band_size || ""}${ oldPerformerDetails?.cup_size ?? "" }`} showDiff={showDiff} /> <ChangeRow name="Waist Size" newValue={performerDetails.waist_size} oldValue={oldPerformerDetails?.waist_size} showDiff={showDiff} /> <ChangeRow name="Hip Size" newValue={performerDetails.hip_size} oldValue={oldPerformerDetails?.hip_size} showDiff={showDiff} /> <ChangeRow name="Nationality" newValue={getCountryByISO(performerDetails.country)} oldValue={getCountryByISO(oldPerformerDetails?.country)} showDiff={showDiff} /> <ChangeRow name="Ethnicity" newValue={ performerDetails.ethnicity && EthnicityTypes[performerDetails.ethnicity as keyof typeof EthnicityEnum] } oldValue={ oldPerformerDetails?.ethnicity && EthnicityTypes[ oldPerformerDetails.ethnicity as keyof typeof EthnicityEnum ] } showDiff={showDiff} /> <ChangeRow name="Career Start" newValue={performerDetails.career_start_year} oldValue={oldPerformerDetails?.career_start_year} showDiff={showDiff} /> <ChangeRow name="Career End" newValue={performerDetails.career_end_year} oldValue={oldPerformerDetails?.career_end_year} showDiff={showDiff} /> <ChangeRow name="Tattoos" newValue={(performerDetails.added_tattoos ?? []) .map(formatBodyModification) .join("\n")} oldValue={(performerDetails.removed_tattoos ?? []) .map(formatBodyModification) .join("\n")} showDiff={showDiff} /> <ChangeRow name="Piercings" newValue={(performerDetails.added_piercings ?? []) .map(formatBodyModification) .join("\n")} oldValue={(performerDetails.removed_piercings ?? []) .map(formatBodyModification) .join("\n")} showDiff={showDiff} /> <URLChangeRow newURLs={performerDetails.added_urls} oldURLs={performerDetails.removed_urls} showDiff={showDiff} /> <ImageChangeRow newImages={performerDetails.added_images} oldImages={performerDetails.removed_images} showDiff={showDiff} /> {performerDetails.draft_id && ( <Row className="mb-2"> <Col xs={{ offset: 2 }}> <h6> <Icon icon={faEdit} color="green" /> <span className="ms-1">Submitted by draft</span> </h6> </Col> </Row> )} </> ); type ScenePerformance = { as?: string | null; performer: Pick< PerformerFragment, "name" | "id" | "gender" | "disambiguation" | "deleted" >; }; export interface SceneDetails { title?: string | null; date?: string | null; production_date?: string | null; duration?: number | null; details?: string | null; director?: string | null; code?: string | null; studio?: { id: string; name: string; } | null; added_performers?: ScenePerformance[] | null; removed_performers?: ScenePerformance[] | null; added_images?: (Image | null)[] | null; removed_images?: (Image | null)[] | null; added_urls?: URL[] | null; removed_urls?: URL[] | null; added_tags?: | { id: string; name: string; description?: string | null; }[] | null; removed_tags?: | { id: string; name: string; description?: string | null; }[] | null; added_fingerprints?: | { algorithm: FingerprintAlgorithm; hash: string; duration: number; }[] | null; removed_fingerprints?: | { algorithm: FingerprintAlgorithm; hash: string; duration: number; }[] | null; draft_id?: string | null; } export type OldSceneDetails = TargetOldDetails<SceneDetails>; export const renderSceneDetails = ( sceneDetails: SceneDetails, oldSceneDetails: OldSceneDetails | undefined, showDiff: boolean, ) => ( <> {sceneDetails.title && ( <ChangeRow name="Title" newValue={sceneDetails.title} oldValue={oldSceneDetails?.title} showDiff={showDiff} /> )} <ChangeRow name="Date" newValue={sceneDetails.date} oldValue={oldSceneDetails?.date} showDiff={showDiff} /> <ChangeRow name="Duration" newValue={formatDuration(sceneDetails.duration)} oldValue={formatDuration(oldSceneDetails?.duration)} showDiff={showDiff} /> <ListChangeRow name="Performers" added={sceneDetails.added_performers} removed={sceneDetails.removed_performers} renderItem={renderPerformer} getKey={(o) => o.performer.id} showDiff={showDiff} /> <LinkedChangeRow name="Studio" newEntity={{ name: sceneDetails.studio?.name, link: sceneDetails.studio && studioHref(sceneDetails.studio), }} oldEntity={{ name: oldSceneDetails?.studio?.name, link: oldSceneDetails?.studio && studioHref(oldSceneDetails.studio), }} showDiff={showDiff} /> <URLChangeRow newURLs={sceneDetails.added_urls} oldURLs={sceneDetails.removed_urls} showDiff={showDiff} /> <ChangeRow name="Details" newValue={sceneDetails.details} oldValue={oldSceneDetails?.details} showDiff={showDiff} /> <ChangeRow name="Director" newValue={sceneDetails.director} oldValue={oldSceneDetails?.director} showDiff={showDiff} /> <ChangeRow name="Production Date" newValue={sceneDetails.production_date} oldValue={oldSceneDetails?.production_date} showDiff={showDiff} /> <ChangeRow name="Studio Code" newValue={sceneDetails.code} oldValue={oldSceneDetails?.code} showDiff={showDiff} /> <ListChangeRow name="Tags" added={sceneDetails.added_tags?.slice().sort(compareByName)} removed={sceneDetails.removed_tags?.slice().sort(compareByName)} renderItem={renderTag} getKey={(o) => o.id} showDiff={showDiff} /> <ImageChangeRow newImages={sceneDetails?.added_images} oldImages={sceneDetails?.removed_images} showDiff={showDiff} /> <ListChangeRow name="Fingerprints" added={sceneDetails.added_fingerprints} removed={sceneDetails.removed_fingerprints} renderItem={renderFingerprint} getKey={(o) => `${o.hash}${o.algorithm}`} showDiff={showDiff} /> {sceneDetails.draft_id && ( <Row className="mb-2"> <Col xs={{ offset: 2 }}> <h6> <Icon icon={faEdit} color="green" /> <span className="ms-1">Submitted by draft</span> </h6> </Col> </Row> )} </> ); export interface StudioDetails { name?: string | null; parent?: { id: string; name: string; } | null; added_images?: (Image | null)[] | null; removed_images?: (Image | null)[] | null; added_urls?: URL[] | null; removed_urls?: URL[] | null; added_aliases?: string[] | null; removed_aliases?: string[] | null; } export type OldStudioDetails = TargetOldDetails<StudioDetails>; export const renderStudioDetails = ( studioDetails: StudioDetails, oldStudioDetails: OldStudioDetails | undefined, showDiff: boolean, ) => ( <> <ChangeRow name="Name" newValue={studioDetails.name} oldValue={oldStudioDetails?.name} showDiff={showDiff} /> <ChangeRow name="Aliases" newValue={studioDetails.added_aliases?.join(", ")} oldValue={studioDetails.removed_aliases?.join(", ")} showDiff={showDiff} /> <LinkedChangeRow name="Network" newEntity={{ name: studioDetails.parent?.name, link: studioDetails.parent && studioHref(studioDetails.parent), }} oldEntity={{ name: oldStudioDetails?.parent?.name, link: oldStudioDetails?.parent && studioHref(oldStudioDetails.parent), }} showDiff={showDiff} /> <URLChangeRow newURLs={studioDetails.added_urls} oldURLs={studioDetails.removed_urls} showDiff={showDiff} /> <ImageChangeRow newImages={studioDetails.added_images} oldImages={studioDetails.removed_images} showDiff={showDiff} /> </> ); interface ModifyEditProps { details: Details | null; oldDetails?: OldDetails | null; options?: Options; } const ModifyEdit: FC<ModifyEditProps> = ({ details, oldDetails, options }) => { if (!details) return null; const showDiff = !!oldDetails; if ( isTagEdit(details) && (isTagEdit(oldDetails) || oldDetails === undefined) ) { return renderTagDetails(details, oldDetails, showDiff); } if ( isPerformerEdit(details) && (isPerformerEdit(oldDetails) || oldDetails === undefined) ) { return renderPerformerDetails( details, oldDetails, showDiff, options?.set_modify_aliases, ); } if ( isStudioEdit(details) && (isStudioEdit(oldDetails) || oldDetails === undefined) ) { return renderStudioDetails(details, oldDetails, showDiff); } if ( isSceneEdit(details) && (isSceneEdit(oldDetails) || oldDetails === undefined) ) { return renderSceneDetails(details, oldDetails, showDiff); } return null; }; export default ModifyEdit; ================================================ FILE: frontend/src/components/editCard/VoteBar.tsx ================================================ import { type FC, useState } from "react"; import { Button, Form } from "react-bootstrap"; import { faCheck } from "@fortawesome/free-solid-svg-icons"; import cx from "classnames"; import { VoteStatusEnum, VoteTypeEnum, useVote, type EditFragment, } from "src/graphql"; import { Icon } from "src/components/fragments"; import { useCurrentUser } from "src/hooks"; const CLASSNAME = "VoteBar"; const CLASSNAME_BUTTON = `${CLASSNAME}-button`; const CLASSNAME_VOTED = `${CLASSNAME}-voted`; const CLASSNAME_SAVE = `${CLASSNAME}-save`; interface Props { edit: EditFragment; } const VoteBar: FC<Props> = ({ edit }) => { const { isVoter, isSelf } = useCurrentUser(); const userVote = (edit.votes ?? []).find((v) => v.user?.id && isSelf(v.user)); const [vote, setVote] = useState<VoteTypeEnum | null>(userVote?.vote ?? null); const [submitVote, { loading: savingVote }] = useVote(); if (edit.status !== VoteStatusEnum.PENDING) return null; const currentVote = ( <h6> <span className="me-2">Current Vote:</span> <span>{`${edit.vote_count > 0 ? "+" : ""}${ edit.vote_count === 0 ? "-" : edit.vote_count }`}</span> </h6> ); // Only show vote total for edit owner and users without vote role if (!isVoter || isSelf(edit.user)) return <div>{currentVote}</div>; const handleSave = () => { if (!vote) return; submitVote({ variables: { input: { id: edit.id, vote, }, }, }); }; return ( <div className={CLASSNAME}> <div className={CLASSNAME_SAVE}> {currentVote} {vote && vote !== userVote?.vote && ( <Button variant="secondary" onClick={handleSave} disabled={savingVote} > <span className="me-2">Save</span> <Icon icon={faCheck} color="green" /> </Button> )} </div> <Form.Group controlId={`${edit.id}-vote-yes`} className={cx(CLASSNAME_BUTTON, { [CLASSNAME_VOTED]: userVote?.vote === VoteTypeEnum.ACCEPT, "bg-success": vote === VoteTypeEnum.ACCEPT, })} onChange={() => setVote(VoteTypeEnum.ACCEPT)} > <Form.Label> <Form.Check type="radio" name={`${edit.id}-vote`} defaultChecked={userVote?.vote === VoteTypeEnum.ACCEPT} /> <span>Yes</span> </Form.Label> </Form.Group> <Form.Group controlId={`${edit.id}-vote-no`} className={cx(CLASSNAME_BUTTON, { [CLASSNAME_VOTED]: userVote?.vote === VoteTypeEnum.REJECT, "bg-danger": vote === VoteTypeEnum.REJECT, })} onChange={() => setVote(VoteTypeEnum.REJECT)} > <Form.Label> <Form.Check type="radio" name={`${edit.id}-vote`} defaultChecked={userVote?.vote === VoteTypeEnum.REJECT} /> <span>No</span> </Form.Label> </Form.Group> <Form.Group controlId={`${edit.id}-vote-abstain`} className={cx(CLASSNAME_BUTTON, { [CLASSNAME_VOTED]: userVote?.vote === VoteTypeEnum.ABSTAIN, "bg-warning": vote === VoteTypeEnum.ABSTAIN, })} onChange={() => setVote(VoteTypeEnum.ABSTAIN)} > <Form.Label> <Form.Check type="radio" name={`${edit.id}-vote`} defaultChecked={userVote?.vote === VoteTypeEnum.ABSTAIN} /> <span>Abstain</span> </Form.Label> </Form.Group> </div> ); }; export default VoteBar; ================================================ FILE: frontend/src/components/editCard/Votes.tsx ================================================ import type { FC } from "react"; import { Link } from "react-router-dom"; import { sortBy } from "lodash-es"; import { VoteTypeEnum, type EditFragment } from "src/graphql"; import { userHref, formatDateTime } from "src/utils"; import { VoteTypes } from "src/constants/enums"; import { Tooltip } from "src/components/fragments"; const CLASSNAME = "EditVotes"; interface VotesProps { edit: EditFragment; } const Votes: FC<VotesProps> = ({ edit }) => ( <> <div className={CLASSNAME}> <h5>Votes:</h5> <div> <b className="me-2">Vote Tally:</b> <b>{edit.votes.filter((v) => v.vote === VoteTypeEnum.ACCEPT).length}</b> <span className="mx-1">yes —</span> <b>{edit.votes.filter((v) => v.vote === VoteTypeEnum.REJECT).length}</b> <span className="ms-1">no</span> </div> {sortBy(edit.votes, (v) => v.date) .filter((v) => v.vote !== VoteTypeEnum.ABSTAIN) .map( (v) => v.user && ( <div key={`${edit.id}${v.user.id}`}> <Tooltip text={formatDateTime(v.date)}> <Link to={userHref(v.user)}>{v.user.name}</Link> </Tooltip> <span className="mx-2">•</span> {VoteTypes[v.vote]} </div> ), )} </div> </> ); export default Votes; ================================================ FILE: frontend/src/components/editCard/index.ts ================================================ import EditCard from "./EditCard"; export default EditCard; ================================================ FILE: frontend/src/components/editCard/renderEntity.tsx ================================================ import { Link } from "react-router-dom"; import type { FingerprintAlgorithm, PerformerFragment } from "src/graphql"; import { performerHref, tagHref, createHref, formatDuration } from "src/utils"; import { GenderIcon, PerformerName, TagLink } from "src/components/fragments"; import { ROUTE_SCENES } from "src/constants"; type Appearance = { performer: PerformerFragment; as: string; }; export const renderPerformer = (appearance: { as?: string | null; performer: Pick< Appearance["performer"], "name" | "id" | "gender" | "disambiguation" | "deleted" >; }) => ( <Link key={appearance.performer.id} to={performerHref(appearance.performer)}> <GenderIcon gender={appearance.performer.gender} /> <PerformerName performer={appearance.performer} as={appearance.as} /> </Link> ); export const renderTag = (tag: { id: string; name: string; description?: string | null; }) => ( <TagLink title={tag.name} link={tagHref(tag)} description={tag.description} /> ); export const renderFingerprint = (fingerprint: { hash: string; duration: number; algorithm: FingerprintAlgorithm; }) => ( <> <Link to={`${createHref(ROUTE_SCENES)}?fingerprint=${fingerprint.hash}`}> {fingerprint.algorithm}: {fingerprint.hash} </Link> <span title={`${fingerprint.duration}s`}> {", duration: "} {formatDuration(fingerprint.duration)} </span> </> ); ================================================ FILE: frontend/src/components/editCard/styles.scss ================================================ .EditComment { background-color: $textfield-bg; margin-top: 1rem; .card-body a { color: $link-color; } blockquote { border-left: 3px solid $muted-gray; padding-left: 1rem; margin-left: 0; font-style: italic; color: $muted-gray; } } .EditDiff { border-radius: 0.25rem; height: 100%; padding: 0.25rem 0.5rem; white-space: pre-wrap; } .VoteBar { display: flex; &-voted { font-weight: bold; } &-save { margin-left: auto; margin-right: 20px; } &-button { margin-right: 8px; margin-top: 8px; min-width: 34px; text-align: center; &:last-child { margin-right: 0; } .form-label { padding: 0.5rem; margin-bottom: 0; } .form-check-input { margin: auto; width: 16px; } .form-label, .form-check-input { &:hover { cursor: pointer; } } } } .EditVotes { margin-bottom: 20px; text-align: right; } .ListChangeRow { &-Tags { ul { list-style-type: none; padding-left: 0; li { display: inline-block; } } } } ================================================ FILE: frontend/src/components/editImages/editImages.tsx ================================================ import { type FC, type ChangeEvent, useState } from "react"; import { Button, Col, Form, Row } from "react-bootstrap"; import { useFieldArray } from "react-hook-form"; import type { Lens } from "@hookform/lenses"; import { CombinedGraphQLErrors } from "@apollo/client"; import { faImages } from "@fortawesome/free-solid-svg-icons"; import cx from "classnames"; import { type ImageFragment as Image, useAddImage } from "src/graphql"; import { Image as ImageInput } from "src/components/form"; import { Icon, LoadingIndicator } from "src/components/fragments"; const CLASSNAME = "EditImages"; const CLASSNAME_IMAGES = `${CLASSNAME}-images`; const CLASSNAME_INPUT = `${CLASSNAME}-input`; const CLASSNAME_INPUT_CONTAINER = `${CLASSNAME_INPUT}-container`; const CLASSNAME_DROP = `${CLASSNAME}-drop`; const CLASSNAME_PLACEHOLDER = `${CLASSNAME}-placeholder`; const CLASSNAME_IMAGE = `${CLASSNAME}-image`; const CLASSNAME_UPLOADING = `${CLASSNAME_IMAGE}-uploading`; interface EditImagesProps { lens: Lens<Image[]>; file: File | undefined; setFile: (f: File | undefined) => void; maxImages?: number; /** Whether to allow svg/png image input */ allowLossless?: boolean; original?: Image[] | undefined; } const EditImages: FC<EditImagesProps> = ({ lens, maxImages, file, setFile, allowLossless = false, original, }) => { const interop = lens.interop(); const { fields: images, append, remove, replace, } = useFieldArray({ control: interop.control, name: interop.name, keyName: "key", }); const [imageData, setImageData] = useState<string>(""); const [uploading, setUploading] = useState(false); const [addImage] = useAddImage(); const [error, setError] = useState<string>(); const handleAddImage = () => { setError(""); setUploading(true); addImage({ variables: { imageData: { file }, }, }) .then((i) => { if (i.data?.imageCreate?.id) { if (!images.some((image) => image.id === i.data?.imageCreate?.id)) { append(i.data.imageCreate); } setFile(undefined); setImageData(""); } }) .catch((error: unknown) => { if (CombinedGraphQLErrors.is(error)) setError(error.message); }) .finally(() => { setUploading(false); }); }; const removeImage = () => { setFile(undefined); setError(""); setImageData(""); }; const onFileChange = (event: ChangeEvent<HTMLInputElement>) => { if (event.target.validity.valid && event.target.files?.[0]) { setFile(event.target.files[0]); const reader = new FileReader(); reader.onload = (e) => e.target?.result && setImageData(e.target.result as string); reader.onerror = () => setImageData(""); reader.onabort = () => setImageData(""); reader.readAsDataURL(event.target.files[0]); } }; const isDisabled = maxImages !== undefined && images.length >= maxImages; return ( <Row className={`${CLASSNAME} w-100`}> <Col xs={7} className={CLASSNAME_IMAGES}> {images.map((i, index) => ( <ImageInput image={i} onRemove={() => remove(index)} key={i.id} /> ))} </Col> <Col xs={5} className={CLASSNAME_INPUT}> <div className={CLASSNAME_INPUT_CONTAINER}> {file ? ( <div className={cx(CLASSNAME_IMAGE, { [CLASSNAME_UPLOADING]: uploading, })} > <img src={imageData} alt="" /> <LoadingIndicator message="Uploading image..." /> </div> ) : ( !isDisabled && ( <div className={CLASSNAME_DROP}> <Form.Control type="file" onChange={onFileChange} accept={[ ".jpg", ".jpeg", ".webp", ".jfif", ...(allowLossless ? [".svg", ".png"] : []), ].join(",")} /> <div className={CLASSNAME_PLACEHOLDER}> <Icon icon={faImages} /> <span>Add image</span> </div> </div> ) )} </div> <Row className="text-end text-danger"> <div>{error}</div> </Row> <div className="mt-4 d-flex"> {file && ( <> <Button variant="danger" onClick={() => removeImage()} disabled={!file || uploading} > Remove </Button> <Button onClick={() => handleAddImage()} disabled={!file || uploading} className="ms-2" > Upload </Button> </> )} <Button variant="danger" onClick={() => original && replace(original)} disabled={original === undefined} className="ms-auto mt-auto" > Reset Images </Button> </div> </Col> </Row> ); }; export default EditImages; ================================================ FILE: frontend/src/components/editImages/index.ts ================================================ import EditImages from "./editImages"; export default EditImages; ================================================ FILE: frontend/src/components/editImages/styles.scss ================================================ .EditImages { &-drop { align-items: center; border: 3px dashed $text-color; border-radius: 10px; display: flex; height: 400px; justify-content: center; margin: auto; position: relative; width: 400px; &:hover { background-color: #394b59; } } &-placeholder { align-items: center; display: flex; flex-direction: column; font-size: 2rem; text-align: center; .fa-images { font-size: 4rem; } } &-images { display: flex; flex-wrap: wrap; justify-content: space-between; } &-input-container { display: flex; min-height: 200px; } &-image { margin: auto; max-height: 600px; max-width: 100%; position: relative; img { max-height: 600px; max-width: 100%; } .LoadingIndicator { display: none; position: absolute; text-align: center; text-shadow: 2px 2px black; top: 40%; } &-uploading { img { opacity: 0.5; } .LoadingIndicator { display: block; opacity: 1; } } } .form-control { cursor: pointer; height: 100%; left: 0; opacity: 0; position: absolute; top: 0; width: 100%; } } ================================================ FILE: frontend/src/components/form/BodyModification.tsx ================================================ // biome-ignore-all lint/correctness/noNestedComponentDefinitions: react-select import type { FC, ChangeEvent } from "react"; import Creatable from "react-select/creatable"; import { components } from "react-select"; import { Button, Col, Form, InputGroup, Row } from "react-bootstrap"; import { useFieldArray } from "react-hook-form"; import type { Lens } from "@hookform/lenses"; export type BodyModItem = { location: string; description?: string | null | undefined; }; interface BodyModificationProps { name: string; lens: Lens<BodyModItem[]>; locationPlaceholder: string; descriptionPlaceholder: string; formatLabel: (text: string) => string; } const CLASSNAME = "BodyModification"; const BodyModification: FC<BodyModificationProps> = ({ name, locationPlaceholder, descriptionPlaceholder, lens, formatLabel, }) => { const interop = lens.interop(); const { fields: modifications, append, remove, update, } = useFieldArray({ control: interop.control, name: interop.name, keyName: "key", }); const isNewLocationValid = (inputValue: string): boolean => !!inputValue && !modifications.find(({ location }) => inputValue === location); const handleNewLocation = (inputValue: string) => { append({ location: inputValue }); }; const modificationList = modifications.map((mod, index) => ( <Row key={mod.location} className="mb-1"> <InputGroup className="col"> <InputGroup.Text className="fw-bold">Location</InputGroup.Text> <Form.Control defaultValue={mod.location} readOnly /> <Form.Control defaultValue={mod.description ?? ""} placeholder={descriptionPlaceholder} onInput={(e: ChangeEvent<HTMLInputElement>) => update(index, { location: mod.location, description: e.currentTarget.value, }) } /> <Button variant="danger" onClick={() => remove(index)}> Remove </Button> </InputGroup> </Row> )); return ( <> <Row className={CLASSNAME}> <Col className="mb-3"> <Form.Label className="text-capitalize">{name}</Form.Label> <Creatable classNamePrefix="react-select" value={null} name={name} placeholder={locationPlaceholder} isValidNewOption={isNewLocationValid} onCreateOption={handleNewLocation} formatCreateLabel={formatLabel} components={{ DropdownIndicator: () => null, Menu: (data) => data.options.length > 0 ? <components.Menu {...data} /> : null, }} /> </Col> </Row> {modificationList} </> ); }; export default BodyModification; ================================================ FILE: frontend/src/components/form/EditNote.tsx ================================================ import type { FC } from "react"; import { Form } from "react-bootstrap"; import cx from "classnames"; import type { FieldError, UseFormRegister } from "react-hook-form"; import NoteInput from "./NoteInput"; interface Props { // biome-ignore lint/suspicious/noExplicitAny: Awkward react-hook-form type register: UseFormRegister<any>; error?: FieldError; } const EditNote: FC<Props> = ({ register, error }) => ( <div className="mb-3"> <Form.Label>Edit Note</Form.Label> <NoteInput className={cx({ "is-invalid": error })} register={register} hasError={!!error?.message} /> <Form.Text> Please add any relevant sources or other supporting information for your edit. </Form.Text> <Form.Control.Feedback type="invalid"> {error?.message} </Form.Control.Feedback> </div> ); export default EditNote; ================================================ FILE: frontend/src/components/form/Image.tsx ================================================ import type { FC } from "react"; import { Button } from "react-bootstrap"; import { faXmark } from "@fortawesome/free-solid-svg-icons"; import { Icon } from "src/components/fragments"; import Image from "src/components/image"; import type { ImageFragment } from "src/graphql"; interface ImageProps { image: Pick<ImageFragment, "id" | "url" | "width" | "height">; onRemove: () => void; } const CLASSNAME = "ImageInput"; const CLASSNAME_IMAGE = `${CLASSNAME}-image`; const CLASSNAME_REMOVE = `${CLASSNAME}-remove`; const ImageInput: FC<ImageProps> = ({ image, onRemove }) => ( <div className={CLASSNAME}> <Button variant="danger" className={CLASSNAME_REMOVE} onClick={() => onRemove()} > <Icon icon={faXmark} /> </Button> <Image images={image} className={CLASSNAME_IMAGE} size="full" /> </div> ); export default ImageInput; ================================================ FILE: frontend/src/components/form/NavButtons.tsx ================================================ import type { FC } from "react"; import { Button } from "react-bootstrap"; import { useNavigate } from "react-router-dom"; interface Props { onNext: () => void; disabled?: boolean; } export const NavButtons: FC<Props> = ({ onNext, disabled = false }) => { const navigate = useNavigate(); return ( <div className="d-flex mt-2"> <Button variant="danger" className="ms-auto me-2" onClick={() => navigate(-1)} > Cancel </Button> <Button className="me-1" onClick={onNext} disabled={disabled}> Next </Button> </div> ); }; ================================================ FILE: frontend/src/components/form/NoteInput.tsx ================================================ import { type FC, type ChangeEvent, useState } from "react"; import { Form, Tabs, Tab } from "react-bootstrap"; import cx from "classnames"; import EditComment from "src/components/editCard/EditComment"; import type { UseFormRegister } from "react-hook-form"; import { useCurrentUser } from "src/hooks"; interface IProps { onChange?: (text: string) => void; className?: string; register?: UseFormRegister<{ note: string }>; hasError?: boolean; } const NoteInput: FC<IProps> = ({ onChange, className, register, hasError = false, }) => { const { user } = useCurrentUser(); const [comment, setComment] = useState(""); const handleChange = (e: ChangeEvent<HTMLTextAreaElement>) => { setComment(e.currentTarget.value); onChange?.(e.currentTarget.value); }; const textareaProps = register ? register("note") : { name: "note" }; const now = new Date().toISOString(); return ( <div className={cx("NoteInput", { "is-invalid": hasError })}> <Tabs id="add-comment"> <Tab eventKey="write" title="Write" className="NoteInput-tab"> <Form.Control as="textarea" className={className} onInput={handleChange} rows={5} {...textareaProps} /> </Tab> <Tab eventKey="preview" title="Preview" unmountOnExit mountOnEnter> <EditComment id={`${user?.id}-${now}`} comment={comment} date={now} user={user} /> </Tab> </Tabs> </div> ); }; export default NoteInput; ================================================ FILE: frontend/src/components/form/SubmitButtons.tsx ================================================ import type { FC } from "react"; import { Button } from "react-bootstrap"; import { useNavigate } from "react-router-dom"; interface Props { disabled?: boolean; } export const SubmitButtons: FC<Props> = ({ disabled = false }) => { const navigate = useNavigate(); return ( <div className="d-flex mt-2"> <Button variant="danger" className="ms-auto me-2" onClick={() => navigate(-1)} > Cancel </Button> <Button type="submit" disabled className="d-none" aria-hidden="true" /> <Button type="submit" disabled={disabled}> Submit Edit </Button> </div> ); }; ================================================ FILE: frontend/src/components/form/index.ts ================================================ export { default as BodyModification } from "./BodyModification"; export { default as Image } from "./Image"; export { default as EditNote } from "./EditNote"; export { default as NoteInput } from "./NoteInput"; export * from "./NavButtons"; export * from "./SubmitButtons"; ================================================ FILE: frontend/src/components/form/styles.scss ================================================ .BodyModification { &-remove { z-index: 2; background: transparent; border: none; color: rgba(0 0 0 / 50%); width: 10%; &:hover { color: rgba(0 0 0 / 80%); } } &-select { width: 100%; } &-label { width: 90%; } &-location { display: inline-block; margin-right: 5%; overflow: hidden; text-overflow: ellipsis; vertical-align: middle; white-space: nowrap; width: 30%; } .form-control { display: inline; width: 65%; } h6 { text-transform: capitalize; } } .ImageInput { margin: 0.5rem; position: relative; max-height: 200px; &-image { border-radius: 3px; height: 200px; } &-remove { z-index: 2; left: 5px; opacity: 0.6; padding: 0 5px; position: absolute; top: 5px; } &:hover &-remove { opacity: 1; } } .NoteInput { .tab-content { padding-bottom: 0; } .EditComment { margin-bottom: 0; } } ================================================ FILE: frontend/src/components/fragments/ErrorMessage.tsx ================================================ import type { FC, ReactNode } from "react"; interface IProps { error: string | ReactNode; } const ErrorMessage: FC<IProps> = ({ error }) => ( <div className="row ErrorMessage"> <h2 className="ErrorMessage-content">Error: {error}</h2> </div> ); export default ErrorMessage; ================================================ FILE: frontend/src/components/fragments/Favorite.tsx ================================================ import type { FC, MouseEvent } from "react"; import { faStar } from "@fortawesome/free-solid-svg-icons"; import { faStar as farStar } from "@fortawesome/free-regular-svg-icons"; import { Button } from "react-bootstrap"; import cx from "classnames"; import { Icon, Tooltip } from "src/components/fragments"; import { useSetFavorite } from "src/graphql"; const CLASSNAME = "FavoriteStar"; interface Props { entity: { id: string; deleted: boolean; is_favorite: boolean; }; entityType: "performer" | "studio"; className?: string; interactable?: boolean; } export const FavoriteStar: FC<Props> = ({ className, entity, entityType, interactable = false, }) => { const [setFavorite] = useSetFavorite(entityType, entity.id); const handleClick = (e: MouseEvent) => { setFavorite({ variables: { id: entity.id, favorite: !entity.is_favorite, }, }); e.preventDefault(); }; if ((!interactable && !entity.is_favorite) || entity.deleted) return null; return ( <Tooltip text={ interactable ? `${entity.is_favorite ? "Remove" : "Add"} Favorite` : "" } > <Button disabled={!interactable} onClick={handleClick} className={cx(CLASSNAME, className)} variant="link" > <Icon icon={entity.is_favorite ? faStar : farStar} color={entity.is_favorite ? "gold" : "white"} /> </Button> </Tooltip> ); }; ================================================ FILE: frontend/src/components/fragments/GenderIcon.tsx ================================================ import type { FC } from "react"; import { faVenus, faTransgender, faMars, faVenusMars, } from "@fortawesome/free-solid-svg-icons"; import Icon from "./Icon"; import type { GenderEnum } from "src/graphql"; import { GenderTypes } from "src/constants"; interface IconProps { gender?: GenderEnum | null; } const GenderIcon: FC<IconProps> = ({ gender }) => { if (gender) { const icon = gender.toLowerCase() === "male" ? faMars : gender.toLowerCase() === "female" ? faVenus : faTransgender; return <Icon icon={icon} title={GenderTypes[gender]} />; } return <Icon icon={faVenusMars} />; }; export default GenderIcon; ================================================ FILE: frontend/src/components/fragments/Help.tsx ================================================ import type { FC } from "react"; import { Button, OverlayTrigger, Popover } from "react-bootstrap"; import { Icon } from "src/components/fragments"; import { faQuestionCircle } from "@fortawesome/free-solid-svg-icons"; interface Props { message: string; } const Help: FC<Props> = ({ message }) => { const renderContent = () => ( <Popover id="help"> <Popover.Body>{message}</Popover.Body> </Popover> ); return ( <OverlayTrigger overlay={renderContent()} placement="bottom" trigger="hover" > <Button variant="link" className="minimal"> <Icon icon={faQuestionCircle} /> </Button> </OverlayTrigger> ); }; export default Help; ================================================ FILE: frontend/src/components/fragments/Icon.tsx ================================================ import type { FC } from "react"; import cx from "classnames"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import type { IconDefinition } from "@fortawesome/fontawesome-svg-core"; interface Props { icon: IconDefinition; className?: string; color?: string; title?: string; variant?: "danger" | "success" | "info" | "warning"; } const Icon: FC<Props> = ({ icon, className, color, title, variant }) => ( <FontAwesomeIcon title={title} icon={icon} className={cx("fa-icon", className, { [`text-${variant}`]: variant })} color={color} /> ); export default Icon; ================================================ FILE: frontend/src/components/fragments/LoadingIndicator.tsx ================================================ import { type FC, useEffect, useState } from "react"; import { Spinner } from "react-bootstrap"; import cx from "classnames"; interface LoadingProps { message?: string; delay?: number; } const CLASSNAME = "LoadingIndicator"; const CLASSNAME_MESSAGE = `${CLASSNAME}-message`; const CLASSNAME_DELAYED = `${CLASSNAME}-delayed`; const LoadingIndicator: FC<LoadingProps> = ({ message, delay = 100 }) => { const [delayed, setDelayed] = useState(delay > 0); useEffect(() => { if (!delayed || delay === 0) return; const timeout = setTimeout(() => setDelayed(false), delay); return () => clearTimeout(timeout); }, [delayed, delay]); return ( <div className={cx(CLASSNAME, { [CLASSNAME_DELAYED]: delayed })}> <Spinner animation="border" role="status"> <span className="visually-hidden">Loading...</span> </Spinner> <h4 className={CLASSNAME_MESSAGE}>{message ?? "Loading..."}</h4> </div> ); }; export default LoadingIndicator; ================================================ FILE: frontend/src/components/fragments/PerformerName.tsx ================================================ import type { FC } from "react"; import type { PerformerFragment } from "src/graphql"; interface PerformerNameProps { performer: Pick<PerformerFragment, "name" | "disambiguation" | "deleted">; as?: string | null; } const PerformerName: FC<PerformerNameProps> = ({ performer, as }) => { if (!as) return ( <> {performer.deleted ? ( <del>{performer.name}</del> ) : ( <span>{performer.name}</span> )} {performer.disambiguation && ( <small className="ms-1 text-small text-muted"> ({performer.disambiguation}) </small> )} </> ); return ( <> <span>{as}</span> <small className="ms-1 text-small text-muted"> ({performer.name}) {performer.disambiguation && ( <small className="ms-1 text-small text-muted"> ({performer.disambiguation}) </small> )} </small> </> ); }; export default PerformerName; ================================================ FILE: frontend/src/components/fragments/SearchHint.tsx ================================================ import type React from "react"; import { faCircleQuestion } from "@fortawesome/free-regular-svg-icons"; import { Icon, Tooltip } from "src/components/fragments"; export const SearchHint: React.FC = () => ( <Tooltip text='Add " to the end to include all words, or paste in a Stash ID'> <div className="SearchHint"> <Icon icon={faCircleQuestion} color="black" /> </div> </Tooltip> ); ================================================ FILE: frontend/src/components/fragments/SearchInput.tsx ================================================ import { components } from "react-select"; import { extractIdFromUrl } from "src/utils"; // Shared Input component for react-select that extracts IDs from pasted stash-box URLs export const SearchInput: typeof components.Input = (props) => ( <components.Input {...props} onPaste={(e) => { const pasted = e.clipboardData.getData("text/plain"); const extracted = extractIdFromUrl(pasted); if (extracted !== pasted) { e.preventDefault(); props.selectProps.onInputChange(extracted, { action: "input-change", prevInputValue: String(props.value ?? ""), }); } }} /> ); ================================================ FILE: frontend/src/components/fragments/SiteLink.tsx ================================================ import type { FC } from "react"; import { Link } from "react-router-dom"; import cx from "classnames"; import { siteHref } from "src/utils/route"; const CLASSNAME = "SiteLink"; const CLASSNAME_ICON = `${CLASSNAME}-icon`; const CLASSNAME_NAME = `${CLASSNAME}-name`; const CLASSNAME_NO_MARGIN = `${CLASSNAME}-no-margin`; interface Props { site: { id: string; name: string; icon: string; } | null; hideName?: boolean; noMargin?: boolean; } const SiteLink: FC<Props> = ({ site, hideName = false, noMargin = false }) => site && ( <Link to={siteHref(site)} className={CLASSNAME}> <img className={CLASSNAME_ICON} src={site.icon} alt="" /> {!hideName && ( <span className={cx(CLASSNAME_NAME, { [CLASSNAME_NO_MARGIN]: noMargin })} > {site.name} </span> )} </Link> ); export default SiteLink; ================================================ FILE: frontend/src/components/fragments/TagLink.tsx ================================================ import type { FC } from "react"; import { Badge, Button } from "react-bootstrap"; import { Link } from "react-router-dom"; import { Icon } from "src/components/fragments"; import { faXmark } from "@fortawesome/free-solid-svg-icons"; import cx from "classnames"; interface IProps { title: string; link?: string; description?: string | null; className?: string; onRemove?: () => void; disabled?: boolean; } const TagLink: FC<IProps> = ({ title, link, description, className, onRemove, disabled = false, }) => ( <Badge className={cx("tag-item", className)} bg="none"> <abbr title={description || undefined}> {link && !disabled ? <Link to={link}>{title}</Link> : title} </abbr> {onRemove && ( <Button onClick={onRemove}> <Icon icon={faXmark} /> </Button> )} </Badge> ); export default TagLink; ================================================ FILE: frontend/src/components/fragments/Thumbnail.tsx ================================================ import type { FC } from "react"; import cx from "classnames"; import { faXmark } from "@fortawesome/free-solid-svg-icons"; import Icon from "./Icon"; interface Props { image?: string; size?: 600 | 300; alt?: string | null; className?: string; orientation?: "portrait" | "landscape"; } const doubleSize = { 300: 600, 600: 1280, }; export const Thumbnail: FC<Props> = ({ image, size, alt, className, orientation = "landscape", }) => image ? ( <img alt={alt ?? ""} className={className} src={image + (size ? `?size=${size}` : "")} srcSet={ size ? `${image}?size=${doubleSize[size]} ${doubleSize[size]}w` : "" } /> ) : ( <div className={cx(className, "Thumbnail-empty")} style={{ aspectRatio: orientation === "landscape" ? "16/9" : "2/3" }} > <Icon icon={faXmark} /> </div> ); ================================================ FILE: frontend/src/components/fragments/Tooltip.tsx ================================================ import type { FC, ReactElement } from "react"; import { OverlayTrigger, Tooltip as BSTooltip, type PopoverProps, } from "react-bootstrap"; interface Props { text: string | ReactElement; placement?: PopoverProps["placement"]; children: ReactElement; delay?: number; } const Tooltip: FC<Props> = ({ children, text, delay = 200, placement = "bottom-end", }) => ( <OverlayTrigger delay={{ show: delay, hide: 0 }} overlay={ <BSTooltip className="Tooltip" id="tooltip"> {text} </BSTooltip> } show={text ? undefined : false} placement={placement} trigger={["hover", "focus"]} > {children} </OverlayTrigger> ); export default Tooltip; ================================================ FILE: frontend/src/components/fragments/index.ts ================================================ export { default as GenderIcon } from "./GenderIcon"; export { default as LoadingIndicator } from "./LoadingIndicator"; export { default as Icon } from "./Icon"; export { default as TagLink } from "./TagLink"; export { default as SiteLink } from "./SiteLink"; export { default as PerformerName } from "./PerformerName"; export { default as ErrorMessage } from "./ErrorMessage"; export { default as Help } from "./Help"; export { default as Tooltip } from "./Tooltip"; export { FavoriteStar } from "./Favorite"; export { Thumbnail } from "./Thumbnail"; export { SearchHint } from "./SearchHint"; export { SearchInput } from "./SearchInput"; ================================================ FILE: frontend/src/components/fragments/styles.scss ================================================ @keyframes fade-in { 0% { opacity: 0; } 100% { opacity: 1; } } .LoadingIndicator { align-items: center; display: flex; flex-direction: column; height: 70vh; justify-content: center; width: 100%; opacity: 1; transition: opacity 1s linear; &-delayed { opacity: 0; } &-message { margin-top: 1rem; } .spinner-border { height: 3rem; width: 3rem; } } .tag-item { background-color: #bfccd6; color: #182026; font-size: 12px; font-weight: 400; line-height: 16px; margin: 5px; padding: 2px 6px; a:hover { color: unset; text-decoration: none; } &:hover { cursor: pointer; } .btn { background: none; border: none; color: #182026; margin: 0; margin-left: 0.25rem; padding: 0 0.5rem; &:hover { background-color: #ffbdad; color: #de350b; } .fa-xmark { width: 0.5rem; } } } .ErrorMessage { align-items: center; height: 20rem; justify-content: center; &-content { display: inline-block; } } .SiteLink { align-items: baseline; display: inline-flex; &-icon { align-self: center; border-radius: 3px; height: 2ex; width: 2ex; margin-right: 5px; } &-name { font-size: 2ex; font-weight: bold; &::after { content: ":"; margin-right: 0.5rem; } } &-no-margin::after { display: none; } } .FavoriteStar { padding: 0; margin-top: -4px; &:disabled { opacity: 1; } &:focus { box-shadow: none; } } .SearchHint { margin-left: 10px; cursor: help; } .Tooltip { position: absolute !important; } .Thumbnail { &-empty { display: flex; width: 100%; height: 100%; color: var(--bs-gray-400); background-color: #394b59; align-items: center; justify-content: center; border-radius: 4px; .fa-icon { height: 30px; max-height: 30%; } } } ================================================ FILE: frontend/src/components/image/Image.tsx ================================================ import { type FC, useState } from "react"; import cx from "classnames"; import { faXmark } from "@fortawesome/free-solid-svg-icons"; import { sortImageURLs } from "src/utils"; import { LoadingIndicator, Icon } from "src/components/fragments"; const CLASSNAME = "Image"; type Image = { url: string; width: number; height: number; }; type ImageSize = 1280 | 600 | 300 | "full"; interface ImageProps { image?: Image; emptyMessage?: string; size?: ImageSize; alt?: string; } const ImageComponent: FC<ImageProps> = ({ image, emptyMessage = "No image", size, alt, }) => { const [imageState, setImageState] = useState<"loading" | "error" | "done">( "loading", ); if (!image?.url) return ( <div className={`${CLASSNAME}-missing`}> <Icon icon={faXmark} color="var(--bs-gray-400)" /> <div>{emptyMessage}</div> </div> ); const sizeQuery = size ? `?size=${size}` : ""; return ( <> {imageState === "loading" && ( <LoadingIndicator message="Loading image..." delay={200} /> )} {imageState === "error" && ( <div className="Image-error"> <Icon icon={faXmark} color="red" /> <div>Failed to load image</div> </div> )} <img alt={alt ?? ""} src={`${image.url}${sizeQuery}`} className={`${CLASSNAME}-image`} onLoad={() => setImageState("done")} onError={() => setImageState("error")} /> </> ); }; interface ContainerProps { images: Image[] | Image | undefined; orientation?: "landscape" | "portrait"; emptyMessage?: string; size?: ImageSize; alt?: string; className?: string; } const ImageContainer: FC<ContainerProps> = ({ className, images, orientation = "landscape", ...props }) => { const image = Array.isArray(images) ? sortImageURLs(images, orientation)[0] : images; const aspectRatio = image ? `${image.width}/${image.height}` : "16/6"; return ( <div className={cx(CLASSNAME, className)} style={{ aspectRatio }}> <ImageComponent {...props} image={image} /> </div> ); }; export default ImageContainer; ================================================ FILE: frontend/src/components/image/index.ts ================================================ export { default } from "./Image"; ================================================ FILE: frontend/src/components/image/styles.scss ================================================ .Image { position: relative; display: flex; max-height: 100%; max-width: 100%; &-image { max-width: 100%; max-height: 100%; z-index: 1; } .LoadingIndicator { position: absolute; background-color: $gray-600; border-radius: 4px; height: 100%; width: 100%; text-align: center; } &-error, &-missing { position: absolute; background-color: $secondary; width: 100%; height: 100%; align-content: center; text-align: center; font-size: 24px; .fa-icon { border-radius: 4px; width: 70px; height: 70px; max-width: 100%; max-height: 100%; } } } ================================================ FILE: frontend/src/components/imageCarousel/ImageCarousel.tsx ================================================ import { type FC, useState } from "react"; import { Button } from "react-bootstrap"; import { faChevronLeft, faChevronRight, } from "@fortawesome/free-solid-svg-icons"; import type { ImageFragment } from "src/graphql"; import Image from "src/components/image"; import { Icon } from "src/components/fragments"; import { sortImageURLs } from "src/utils"; interface ImageCarouselProps { images: ImageFragment[]; orientation?: "portrait" | "landscape"; } const ImageCarousel: FC<ImageCarouselProps> = ({ images, orientation }) => { const [imageIndex, setImageIndex] = useState(0); const sortedImages = orientation ? sortImageURLs(images, orientation) : images; if (sortedImages.length === 0) return <div />; const changeImage = (index: number) => { setImageIndex(index); }; const setNext = () => changeImage(imageIndex === sortedImages.length - 1 ? 0 : imageIndex + 1); const setPrev = () => changeImage(imageIndex === 0 ? sortedImages.length - 1 : imageIndex - 1); return ( <div className="image-carousel"> <div className="image-container"> <Button className="prev-button minimal" onClick={setPrev} disabled={sortedImages.length === 1} variant="link" > <Icon icon={faChevronLeft} /> </Button> <div className="image-carousel-img"> <Image images={sortedImages[imageIndex]} key={sortedImages[imageIndex].url} size={600} /> </div> <Button className="next-button minimal" onClick={setNext} disabled={sortedImages.length === 1} variant="link" > <Icon icon={faChevronRight} /> </Button> </div> <h5 className="text-center"> {imageIndex + 1} of {sortedImages.length} </h5> </div> ); }; export default ImageCarousel; ================================================ FILE: frontend/src/components/imageCarousel/index.ts ================================================ import ImageCarousel from "./ImageCarousel"; export default ImageCarousel; ================================================ FILE: frontend/src/components/imageCarousel/styles.scss ================================================ .image-carousel { height: 100%; width: 100%; .image-container { align-items: center; display: flex; flex-direction: row; height: 100%; justify-content: center; position: relative; width: 100%; } &-img { display: flex; flex-grow: 1; height: 100%; justify-content: center; width: 0; img { border-radius: 3px; max-height: 100%; max-width: 100%; object-fit: contain; object-position: center; } } .carousel { height: 80%; width: inherit; .slide { align-items: center; display: flex; justify-content: center; } .slider img { width: inherit; } } .slider-wrapper, .slider { height: 100%; } .prev-button { padding-left: 0; } .next-button { padding-right: 0; } .prev-button, .next-button { .fa-icon { height: 4rem; opacity: 0.4; width: 2rem; } &:focus { box-shadow: none; } &:hover { background-color: transparent; filter: drop-shadow(2px 2px 2px black); .fa-icon { opacity: 1; } } } } ================================================ FILE: frontend/src/components/imageChangeRow/ImageChangeRow.tsx ================================================ import type { FC } from "react"; import { Col, Row } from "react-bootstrap"; import ImageComponent from "src/components/image"; type Image = { height: number; id: string; url: string; width: number; }; const CLASSNAME = "ImageChangeRow"; const CLASSNAME_IMAGE = `${CLASSNAME}-image`; export interface ImageChangeRowProps { newImages?: (Image | null)[] | null; oldImages?: (Image | null)[] | null; showDiff?: boolean; } const Images: FC<{ images: (Image | null)[] | null | undefined; }> = ({ images }) => { return ( <> {(images ?? []).map((image, i) => image === null ? ( // biome-ignore lint/suspicious/noArrayIndexKey: Image is deleted, no other key <img className={CLASSNAME_IMAGE} alt="Deleted" key={`deleted-${i}`} /> ) : ( <div key={image.id} className={CLASSNAME_IMAGE}> <ImageComponent images={image} alt="" size="full" /> <div className="text-center"> {image.width} x {image.height} </div> </div> ), )} </> ); }; const ImageChangeRow: FC<ImageChangeRowProps> = ({ newImages, oldImages, showDiff = false, }) => (newImages ?? []).length > 0 || (oldImages ?? []).length > 0 ? ( <Row className={CLASSNAME}> <b className="col-2 text-end">Images</b> {showDiff && ( <Col xs={5}> {(oldImages ?? []).length > 0 && ( <> <h6>Removed</h6> <div className={CLASSNAME}> <Images images={oldImages} /> </div> </> )} </Col> )} <Col xs={showDiff ? 5 : 10}> {(newImages ?? []).length > 0 && ( <> {showDiff && <h6>Added</h6>} <div className={CLASSNAME}> <Images images={newImages} /> </div> </> )} </Col> </Row> ) : null; export default ImageChangeRow; ================================================ FILE: frontend/src/components/imageChangeRow/index.ts ================================================ export { default } from "./ImageChangeRow"; ================================================ FILE: frontend/src/components/imageChangeRow/styles.scss ================================================ .ImageChangeRow { display: flex; flex-wrap: wrap; .Image { height: 150px; margin: 5px; width: auto; } } ================================================ FILE: frontend/src/components/linkedChangeRow/LinkedChangeRow.tsx ================================================ import type { FC } from "react"; import { Link } from "react-router-dom"; import { Col, Row } from "react-bootstrap"; import cx from "classnames"; interface Change { name: string | null | undefined; link: string | null | undefined; } interface LinkedChangeRowProps { name: string; oldEntity?: Change | null; newEntity?: Change | null; showDiff?: boolean; } const LinkedChangeRow: FC<LinkedChangeRowProps> = ({ name, newEntity, oldEntity, showDiff = false, }) => { function getValue(value: Change | null | undefined) { if (!value?.name) { return; } if (!value.link) { return value.name; } return <Link to={value.link}>{value.name}</Link>; } if (!newEntity?.link && !oldEntity?.link) return null; return ( <Row className="mb-2"> <b className="col-2 text-end pt-1">{name}</b> {showDiff && ( <Col xs={5} className="ms-auto" key={oldEntity?.name}> <div className="EditDiff bg-danger">{getValue(oldEntity)}</div> </Col> )} <Col xs={showDiff ? 5 : 10} key={newEntity?.name}> <div className={cx("EditDiff", { "bg-success": showDiff })}> {getValue(newEntity)} </div> </Col> </Row> ); }; export default LinkedChangeRow; ================================================ FILE: frontend/src/components/linkedChangeRow/index.ts ================================================ export { default } from "./LinkedChangeRow"; ================================================ FILE: frontend/src/components/list/EditList.tsx ================================================ import type { FC } from "react"; import { useEditFilter, usePagination } from "src/hooks"; import { useEdits, type TargetTypeEnum, type SortDirectionEnum, type VoteStatusEnum, type OperationEnum, type EditSortEnum, type UserVotedFilterEnum, } from "src/graphql"; import { ErrorMessage } from "src/components/fragments"; import EditCard from "src/components/editCard"; import List from "./List"; interface EditsProps { id?: string; sort?: EditSortEnum; direction?: SortDirectionEnum; type?: TargetTypeEnum; status?: VoteStatusEnum; operation?: OperationEnum; voted?: UserVotedFilterEnum; userId?: string; defaultVoteStatus?: VoteStatusEnum; defaultVoted?: UserVotedFilterEnum; defaultBot?: "include" | "exclude" | "only"; showVotedFilter?: boolean; userSubmitted?: boolean; defaultUserSubmitted?: boolean; } const PER_PAGE = 20; const EditListComponent: FC<EditsProps> = ({ id, sort, direction, type, status, operation, voted, userId, defaultVoteStatus, defaultVoted, defaultBot, showVotedFilter, userSubmitted, defaultUserSubmitted, }) => { const { page, setPage } = usePagination(); const { editFilter, selectedSort, selectedDirection, selectedType, selectedOperation, selectedVoted, selectedStatus, selectedFavorite, selectedBot, selectedUserSubmitted, } = useEditFilter({ sort, direction, type, status, operation, voted, showFavoriteOption: id === undefined, showVotedFilter, defaultVoteStatus, defaultVoted, defaultBot, userSubmitted, defaultUserSubmitted, }); const { data, loading } = useEdits({ input: { target_type: selectedType, target_id: id, status: selectedStatus, operation: selectedOperation, voted: selectedVoted, user_id: userId, is_favorite: selectedFavorite, is_bot: selectedBot === "only" ? true : selectedBot === "exclude" ? false : undefined, page, per_page: PER_PAGE, sort: selectedSort, direction: selectedDirection, include_user_submitted: selectedUserSubmitted, }, }); if (!loading && !data) return <ErrorMessage error="Failed to load edits." />; const edits = data?.queryEdits?.edits.map((edit) => ( <EditCard edit={edit} key={edit.id} /> )) ?? []; return ( <List entityName="edits" loading={loading} listCount={data?.queryEdits.count} filters={editFilter} page={page} setPage={setPage} perPage={PER_PAGE} > <div>{edits}</div> </List> ); }; export default EditListComponent; ================================================ FILE: frontend/src/components/list/List.tsx ================================================ import { type FC, type ReactNode, useEffect, useState } from "react"; import { LoadingIndicator } from "src/components/fragments"; import Pagination from "src/components/pagination"; const PER_PAGE = 20; interface Props { page: number; setPage: (page: number) => void; perPage?: number; listCount?: number; loading: boolean; filters?: ReactNode; entityName?: string; children?: React.ReactNode; } const List: FC<Props> = ({ page, setPage, perPage = PER_PAGE, listCount, loading, filters, children, entityName = "data", }) => { const [count, setCount] = useState<number | undefined>(listCount); useEffect(() => { if (!loading && listCount !== undefined) setCount(listCount); }, [loading, listCount]); const currentCount = count ?? listCount; return ( <div className={`${entityName}-list`}> <div className="d-flex mt-2 align-items-start flex-wrap"> {filters} <Pagination onClick={setPage} count={currentCount ?? 0} active={page} perPage={perPage} showCount /> </div> {loading ? ( <LoadingIndicator message={`Loading ${entityName}...`} /> ) : currentCount && currentCount > 0 ? ( children ) : currentCount === 0 ? ( <h4 className="m-4 p-4 text-center">No results</h4> ) : null} <div className="d-flex"> <Pagination onClick={setPage} count={currentCount ?? 0} perPage={perPage} active={page} /> </div> </div> ); }; export default List; ================================================ FILE: frontend/src/components/list/SceneList.tsx ================================================ import type { FC } from "react"; import Select from "react-select"; import { Button, Col, Form, InputGroup, Row } from "react-bootstrap"; import { faSortAmountUp, faSortAmountDown, } from "@fortawesome/free-solid-svg-icons"; import { useScenes, FavoriteFilter, type SceneQueryInput, SortDirectionEnum, SceneSortEnum, CriterionModifier, } from "src/graphql"; import { usePagination, useQueryParams } from "src/hooks"; import { ensureEnum } from "src/utils"; import SceneCard from "src/components/sceneCard"; import TagFilter from "src/components/tagFilter"; import { ErrorMessage, Icon } from "src/components/fragments"; import List from "./List"; const PER_PAGE = 20; interface Props { perPage?: number; filter?: Partial<SceneQueryInput>; favoriteFilter?: "performer" | "studio" | "all"; tagsFilter?: SceneQueryInput["tags"]; } const sortOptions = [ { value: SceneSortEnum.DATE, label: "Release Date" }, { value: SceneSortEnum.TITLE, label: "Title" }, { value: SceneSortEnum.TRENDING, label: "Trending" }, { value: SceneSortEnum.CREATED_AT, label: "Created At" }, { value: SceneSortEnum.UPDATED_AT, label: "Updated At" }, ]; const favoriteOptions = [ { label: "All Favorites", value: FavoriteFilter.ALL, }, { label: "Favorite Performers", value: FavoriteFilter.PERFORMER, }, { label: "Favorite Studios", value: FavoriteFilter.STUDIO, }, ]; const SceneList: FC<Props> = ({ perPage = PER_PAGE, filter, favoriteFilter, tagsFilter, }) => { const [params, setParams] = useQueryParams({ sort: { name: "sort", type: "string", default: SceneSortEnum.DATE }, dir: { name: "dir", type: "string", default: SortDirectionEnum.DESC }, favorite: { name: "favorite", type: "string", default: "NONE" }, tag: { name: "tag", type: "string" }, }); const sort = ensureEnum(SceneSortEnum, params.sort); const direction = ensureEnum(SortDirectionEnum, params.dir); const favorite = params.favorite !== "NONE" && ensureEnum(FavoriteFilter, params.favorite); const { page, setPage } = usePagination(); const { loading, data } = useScenes({ input: { page, per_page: perPage, sort, direction, ...filter, favorites: (favoriteFilter !== undefined && favorite) || undefined, tags: tagsFilter || (params.tag ? { value: [params.tag], modifier: CriterionModifier.INCLUDES } : undefined), }, }); if (!loading && !data) return <ErrorMessage error="Failed to load scenes." />; const filters = ( <> {!tagsFilter && ( <TagFilter tag={params.tag} onChange={(t) => setParams("tag", t?.id)} /> )} <InputGroup className="scene-sort w-auto"> <Form.Select className="w-auto" onChange={(e) => setParams("sort", e.currentTarget.value.toLowerCase()) } defaultValue={sort ?? "name"} > {sortOptions.map((s) => ( <option value={s.value} key={s.value}> {s.label} </option> ))} </Form.Select> <Button variant="secondary" onClick={() => setParams( "dir", direction === SortDirectionEnum.DESC ? SortDirectionEnum.ASC : SortDirectionEnum.DESC, ) } > <Icon icon={ direction === SortDirectionEnum.DESC ? faSortAmountDown : faSortAmountUp } /> </Button> </InputGroup> {favoriteFilter === "performer" || favoriteFilter === "studio" ? ( <Form.Group controlId="favorite" className="ms-3"> <Form.Check className="mt-2" type="switch" label={`Only favorite ${favoriteFilter}s`} defaultChecked={!!favorite} onChange={(e) => setParams( "favorite", e.currentTarget.checked ? favoriteFilter.toUpperCase() : "NONE", ) } /> </Form.Group> ) : favoriteFilter === "all" ? ( <Select className="FavoriteFilter ms-4" classNamePrefix="react-select" onChange={(val) => setParams("favorite", val ? val.value : "NONE")} placeholder="Favorite filter" isClearable defaultValue={ favorite ? favoriteOptions.find((fav) => fav.value === favorite) : undefined } options={favoriteOptions} /> ) : null} </> ); const scenes = (data?.queryScenes.scenes ?? []).map((scene) => ( <Col xs={3} key={scene.id}> <SceneCard scene={scene} /> </Col> )); return ( <List page={page} setPage={setPage} perPage={perPage} listCount={data?.queryScenes.count} loading={loading} filters={filters} entityName="scenes" > <Row>{scenes}</Row> </List> ); }; export default SceneList; ================================================ FILE: frontend/src/components/list/TagList.tsx ================================================ import type { FC } from "react"; import { Link } from "react-router-dom"; import { Card, Form, Row } from "react-bootstrap"; import { debounce } from "lodash-es"; import { useTags, SortDirectionEnum, TagSortEnum, type TagQueryInput, } from "src/graphql"; import { usePagination, useQueryParams } from "src/hooks"; import { ErrorMessage } from "src/components/fragments"; import { createHref, tagHref } from "src/utils/route"; import { ROUTE_CATEGORIES } from "src/constants/route"; import List from "./List"; const PER_PAGE = 40; interface TagListProps { tagFilter: Partial<TagQueryInput>; showCategoryLink?: boolean; } const TagList: FC<TagListProps> = ({ tagFilter, showCategoryLink = false }) => { const [{ name }, setParams] = useQueryParams({ name: { name: "query", type: "string", default: "" }, }); const { page, setPage } = usePagination(); const { loading, data } = useTags({ input: { names: name.trim(), page, per_page: PER_PAGE, sort: TagSortEnum.NAME, direction: SortDirectionEnum.ASC, ...tagFilter, }, }); const tags = (data?.queryTags?.tags ?? []).map((tag) => ( <li key={tag.id}> <Link to={tagHref(tag)}>{tag.name}</Link> {tag.description && ( <span className="ms-2"> • <small className="ms-2">{tag.description}</small> </span> )} </li> )); const debouncedHandler = debounce(setParams, 200); const filters = ( <Form.Control id="tag-query" onChange={(e) => debouncedHandler("name", e.currentTarget.value)} placeholder="Filter tag name" defaultValue={name} className="w-25" /> ); if (!loading && !data) return <ErrorMessage error="Failed to load tags." />; return ( <List entityName="tags" page={page} setPage={setPage} perPage={PER_PAGE} filters={filters} loading={loading} listCount={data?.queryTags.count} > <Card> <Card.Body className="pt-4"> <Row className="g-0"> {showCategoryLink && ( <Link to={createHref(ROUTE_CATEGORIES)} className="ms-2"> <h5>List of Categories</h5> </Link> )} </Row> <ul>{tags}</ul> </Card.Body> </Card> </List> ); }; export default TagList; ================================================ FILE: frontend/src/components/list/URLList.tsx ================================================ import type { FC } from "react"; import { SiteLink } from "src/components/fragments"; interface URLListProps { urls: { url: string; site: { id: string; name: string; icon: string; } | null; }[]; } const URLList: FC<URLListProps> = ({ urls }) => ( <ul className="URLList"> {urls.map((u) => ( <li key={u.url}> <SiteLink site={u.site} /> <a href={u.url} target="_blank" rel="noreferrer noopener"> {u.url} </a> </li> ))} </ul> ); export default URLList; ================================================ FILE: frontend/src/components/list/index.ts ================================================ export { default as List } from "./List"; export { default as SceneList } from "./SceneList"; export { default as TagList } from "./TagList"; export { default as EditList } from "./EditList"; export { default as URLList } from "./URLList"; ================================================ FILE: frontend/src/components/list/styles.scss ================================================ .URLList { list-style-type: none; padding: 0; img { width: 16px; } } .FavoriteFilter { width: 240px; } .BotFilter { width: 120px; } ================================================ FILE: frontend/src/components/listChangeRow/ListChangeRow.tsx ================================================ import type { PropsWithChildren } from "react"; import { Col, Row } from "react-bootstrap"; interface ListChangeRowProps<T> { added?: T[] | null; removed?: T[] | null; renderItem: (o: T) => JSX.Element | undefined; getKey: (o: T) => string; name: string; showDiff?: boolean; } const CLASSNAME = "ListChangeRow"; // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-constraint const ListChangeRow = <T,>({ added, removed, name, getKey, renderItem, showDiff, }: PropsWithChildren<ListChangeRowProps<T>>) => (added ?? []).length > 0 || (removed ?? []).length > 0 ? ( <Row className={`${CLASSNAME}-${name}`}> <b className="col-2 text-end">{name}</b> {showDiff && ( <Col xs={5}> {(removed ?? []).length > 0 && ( <> <h6>Removed</h6> <div className={CLASSNAME}> <ul> {(removed ?? []).map((u) => ( <li key={getKey(u)}>{renderItem(u)}</li> ))} </ul> </div> </> )} </Col> )} <Col xs={showDiff ? 5 : 10}> {(added ?? []).length > 0 && ( <> {showDiff && <h6>Added</h6>} <div className={CLASSNAME}> <ul> {(added ?? []).map((u) => ( <li key={getKey(u)}>{renderItem(u)}</li> ))} </ul> </div> </> )} </Col> </Row> ) : null; export default ListChangeRow; ================================================ FILE: frontend/src/components/listChangeRow/index.ts ================================================ export { default } from "./ListChangeRow"; ================================================ FILE: frontend/src/components/modal/Modal.tsx ================================================ import type { ReactNode, FC } from "react"; import { Modal, Button } from "react-bootstrap"; interface ModalProps { callback: (status: boolean) => void; cancelTerm?: string; acceptTerm?: string; } interface MessageProps { message: string; children?: never; } interface ElementProps { children: ReactNode; message?: never; } const ModalComponent: FC<ModalProps & (MessageProps | ElementProps)> = ({ message, children, callback, cancelTerm = "Cancel", acceptTerm = "Delete", }) => { const handleCancel = () => callback(false); const handleAccept = () => callback(true); const content = message || children; return ( <Modal show onHide={handleCancel}> <Modal.Header closeButton> <b>Warning</b> </Modal.Header> <Modal.Body>{content}</Modal.Body> <Modal.Footer> <Button variant="danger" onClick={handleAccept}> {acceptTerm} </Button> <Button variant="primary" onClick={handleCancel}> {cancelTerm} </Button> </Modal.Footer> </Modal> ); }; export default ModalComponent; ================================================ FILE: frontend/src/components/modal/index.ts ================================================ import Modal from "./Modal"; export default Modal; ================================================ FILE: frontend/src/components/multiSelect/MultiSelect.tsx ================================================ // biome-ignore-all lint/correctness/noNestedComponentDefinitions: react-select import type { FC } from "react"; import CreatableSelect from "react-select/creatable"; import type { OnChangeValue } from "react-select"; interface MultiSelectProps { initialValues: string[]; onChange: (values: string[]) => void; placeholder?: string; } interface IOptionType { label: string; value: string; } const MultiSelect: FC<MultiSelectProps> = ({ initialValues, onChange, placeholder = "Select...", }) => { const options: IOptionType[] = (initialValues ?? []).map((value) => ({ label: value, value, })); const handleChange = (values: OnChangeValue<IOptionType, true>) => { if (!values) { onChange([]); return; } onChange(values.map((v) => v.value)); }; /** Allow creating a new option with a different casing. */ const isValidNewOption = ( inputValue: string, selectValue: OnChangeValue<IOptionType, true>, ): boolean => !!inputValue && !selectValue.some( ({ value }) => value.toLowerCase() === inputValue.toLowerCase(), ); return ( <div> <CreatableSelect isMulti classNamePrefix="react-select" className="react-select" defaultValue={options} options={options} isValidNewOption={isValidNewOption} onChange={handleChange} placeholder={placeholder} noOptionsMessage={() => null} formatCreateLabel={(value: string) => `Add '${value}'`} components={{ DropdownIndicator: () => null, IndicatorSeparator: () => null, }} /> </div> ); }; export default MultiSelect; ================================================ FILE: frontend/src/components/multiSelect/index.ts ================================================ import MultiSelect from "./MultiSelect"; export default MultiSelect; ================================================ FILE: frontend/src/components/multiSelect/styles.scss ================================================ .TagSelect { margin-top: 0.5rem; &-list { margin-bottom: 1rem; } &-container { display: flex; } &-select { display: inline-block; margin-left: auto; width: 25rem; } } ================================================ FILE: frontend/src/components/pagination/Pagination.tsx ================================================ import type { FC, MouseEvent } from "react"; import { Pagination } from "react-bootstrap"; interface PaginationProps { active: number; onClick: (page: number) => void; count: number; perPage: number; showCount?: boolean; } const PaginationComponent: FC<PaginationProps> = ({ active, perPage, onClick, count, showCount = false, }) => { const pages = Math.ceil(count / perPage); const totalPages = pages === 0 ? 1 : pages; const showFirst = totalPages > 5 && active > 3; const showLast = totalPages > 5 && active < totalPages - 3; const maxVal = Math.max( Math.min(active + 2, totalPages), Math.min(totalPages, 5), ); const minVal = Math.max(maxVal - 4, 1); const totalItems = maxVal - minVal + 1; // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const paginationItems = [...Array(totalItems)].map((_, arrayIndex) => { const index = arrayIndex + minVal; const isActive = active === index; return ( <Pagination.Item key={index} data-page={index} active={isActive}> {index} </Pagination.Item> ); }); const handleClick = (e: MouseEvent<HTMLUListElement>): void => { const page = (e.target as HTMLElement).closest("a")?.dataset.page; if (!page) return; const pageNumber = page ? Number.parseInt(page, 10) : 1; if (pageNumber !== active) onClick(pageNumber); }; return ( <div className="ms-auto mt-auto d-flex"> {showCount && count > 0 && ( <b className="me-4 mt-2"> {new Intl.NumberFormat().format(count)} results </b> )} <Pagination onClick={handleClick}> {showFirst && <Pagination.First data-page={1} />} <Pagination.Prev disabled={active === 1} data-page={active - 1} /> {paginationItems} <Pagination.Next disabled={active === totalPages} data-page={active + 1} /> {showLast && <Pagination.Last data-page={totalPages} />} </Pagination> </div> ); }; export default PaginationComponent; ================================================ FILE: frontend/src/components/pagination/index.ts ================================================ import Pagination from "./Pagination"; export default Pagination; ================================================ FILE: frontend/src/components/performerCard/PerformerCard.tsx ================================================ import type { FC } from "react"; import { Card } from "react-bootstrap"; import { Link } from "react-router-dom"; import cx from "classnames"; import type { Performer } from "src/graphql"; import { GenderIcon, FavoriteStar, PerformerName, Thumbnail, } from "src/components/fragments"; import { getImage, performerHref } from "src/utils"; type PerformerType = Pick< Performer, "id" | "name" | "images" | "gender" | "is_favorite" | "deleted" >; interface PerformerCardProps { performer: PerformerType; className?: string; } const CLASSNAME = "PerformerCard"; const CLASSNAME_IMAGE = `${CLASSNAME}-image`; const CLASSNAME_STAR = `${CLASSNAME}-star`; const PerformerCard: FC<PerformerCardProps> = ({ className, performer }) => ( <Card className={cx(CLASSNAME, className)}> <Link to={performerHref(performer)}> <div className={CLASSNAME_IMAGE}> <Thumbnail image={getImage(performer.images, "portrait")} alt={performer.name} size={300} orientation="portrait" /> <FavoriteStar entity={performer} entityType="performer" className={CLASSNAME_STAR} /> </div> <Card.Footer> <h5 className="my-1"> <GenderIcon gender={performer.gender} /> <PerformerName performer={performer} /> </h5> </Card.Footer> </Link> </Card> ); export default PerformerCard; ================================================ FILE: frontend/src/components/performerCard/index.ts ================================================ import PerformerCard from "./PerformerCard"; export default PerformerCard; ================================================ FILE: frontend/src/components/performerCard/styles.scss ================================================ .PerformerCard { &-image { align-items: center; display: flex; aspect-ratio: 2 / 3; img { height: 100%; image-rendering: smooth; object-fit: cover; object-position: top; width: 100%; &[src=""] { display: none; } } } &-star { position: absolute; top: 0.5rem; right: 0.5rem; z-index: 1; } } ================================================ FILE: frontend/src/components/performerSelect/PerformerSelect.tsx ================================================ import { type FC, useState } from "react"; import { TagLink } from "src/components/fragments"; import SearchField, { SearchType } from "src/components/searchField"; import { formatDisambiguation, performerHref } from "src/utils"; import type { SearchPerformersQuery } from "src/graphql"; type Performer = NonNullable< SearchPerformersQuery["searchPerformers"]["performers"][number] >; interface PerformerSelectProps { performers: Performer[]; onChange: (performers: Performer[]) => void; message?: string; excludePerformers?: string[]; } const CLASSNAME = "PerformerSelect"; const CLASSNAME_LIST = `${CLASSNAME}-list`; const CLASSNAME_CONTAINER = `${CLASSNAME}-container`; const PerformerSelect: FC<PerformerSelectProps> = ({ performers: initialPerformers, onChange, message = "Add performer:", excludePerformers = [], }) => { const [performers, setPerformers] = useState(initialPerformers); const handleChange = (performer: Performer) => { const newPerformers = [...performers, performer]; setPerformers(newPerformers); onChange(newPerformers); }; const removePerformer = (id: string) => { const newPerformers = performers.filter((performer) => performer.id !== id); setPerformers(newPerformers); onChange(newPerformers); }; const performerList = [...(performers ?? [])] .sort((a, b) => (a.name > b.name ? 1 : a.name < b.name ? -1 : 0)) .map((performer) => ( <TagLink title={`${performer.name}${formatDisambiguation(performer)}`} link={performerHref(performer)} onRemove={() => removePerformer(performer.id)} key={performer.id} disabled /> )); return ( <div className={CLASSNAME}> <div className={CLASSNAME_CONTAINER}> <SearchField onClickPerformer={handleChange} searchType={SearchType.Performer} excludeIDs={excludePerformers} placeholder={message} /> </div> <div className={CLASSNAME_LIST}>{performerList}</div> </div> ); }; export default PerformerSelect; ================================================ FILE: frontend/src/components/performerSelect/index.ts ================================================ import PerformerSelect from "./PerformerSelect"; export default PerformerSelect; ================================================ FILE: frontend/src/components/performerSelect/styles.scss ================================================ .PerformerSelect { margin-top: 0.5rem; &-list { margin: 0.5rem 0; } &-container { display: flex; } &-select { display: inline-block; margin-left: auto; width: 25rem; } } ================================================ FILE: frontend/src/components/sceneCard/SceneCard.tsx ================================================ import type { FC } from "react"; import { Link } from "react-router-dom"; import { Card } from "react-bootstrap"; import { faVideo } from "@fortawesome/free-solid-svg-icons"; import type { Scene, Studio } from "src/graphql"; import { getImage, sceneHref, studioHref, formatDuration, imageType, } from "src/utils"; import { Icon, Thumbnail } from "src/components/fragments"; type Performance = Pick< Scene, "id" | "title" | "images" | "duration" | "release_date" > & { studio?: Pick<Studio, "id" | "name"> | null; }; const CLASSNAME = "SceneCard"; const CLASSNAME_IMAGE = `${CLASSNAME}-image`; const CLASSNAME_BODY = `${CLASSNAME}-body`; const SceneCard: FC<{ scene: Performance }> = ({ scene }) => ( <Card className={CLASSNAME}> <Card.Body className={CLASSNAME_BODY}> <Link className={CLASSNAME_IMAGE} to={sceneHref(scene)}> <Thumbnail alt={scene.title} className={imageType(scene.images[0])} image={getImage(scene.images, "landscape")} size={300} /> </Link> </Card.Body> <Card.Footer> <div className="d-flex"> <Link className="text-truncate w-100" to={sceneHref(scene)} title={scene.title ?? ""} > <h6 className="text-truncate">{scene.title}</h6> </Link> <span className="text-muted"> {scene.duration ? formatDuration(scene.duration) : ""} </span> </div> <div className="text-muted"> {scene.studio && ( <Link to={studioHref(scene.studio)} className="float-end text-truncate SceneCard-studio-name" > <Icon icon={faVideo} className="me-1" /> {scene.studio.name} </Link> )} <strong>{scene.release_date}</strong> </div> </Card.Footer> </Card> ); export default SceneCard; ================================================ FILE: frontend/src/components/sceneCard/index.ts ================================================ import SceneCard from "./SceneCard"; export default SceneCard; ================================================ FILE: frontend/src/components/sceneCard/styles.scss ================================================ .SceneCard { &.card { box-shadow: none; border-radius: 0; background-color: transparent; } &-body { min-height: 150px; padding: 0; } &-image { align-items: center; aspect-ratio: 16/9; display: flex; height: 100%; justify-content: center; width: 100%; img { height: 100%; image-rendering: smooth; object-fit: cover; object-position: center; width: 100%; } .vertical-img { background-color: rgba(0 0 0 / 50%); object-fit: scale-down; } } .card-footer { font-size: 0.8rem; padding: 0.75rem 0; } &-studio-name { max-width: 65%; } } ================================================ FILE: frontend/src/components/searchField/SearchField.tsx ================================================ import { type FC, type KeyboardEvent, useRef, useState } from "react"; import { useApolloClient } from "@apollo/client/react"; import { type OnChangeValue, components, type SelectInstance, type GroupBase, } from "react-select"; import Async from "react-select/async"; import debounce from "p-debounce"; import { useNavigate } from "react-router-dom"; import SearchAllGQL from "src/graphql/queries/SearchAll.gql"; import SearchPerformersGQL from "src/graphql/queries/SearchPerformers.gql"; import type { SearchAllQuery, SearchPerformersQuery } from "src/graphql"; import { getImage } from "src/utils"; import { GenderIcon, SearchHint, SearchInput, Thumbnail, } from "src/components/fragments"; import { handleResult, type SearchResult, type PerformerResult, type SceneResult, } from "./handleResult"; export type { PerformerResult, SceneResult }; export enum SearchType { Performer = "performer", Combined = "combined", } interface SearchFieldProps { onClick?: (result: SceneResult | PerformerResult) => void; onClickPerformer?: (result: PerformerResult) => void; searchType: SearchType; excludeIDs?: string[]; nav?: boolean; placeholder?: string; showAllLink?: boolean; autoFocus?: boolean; /** When provided, performers who have performed for this studio's network will be sorted to the top */ studioId?: string; } const ValueContainer: typeof components.ValueContainer = (props) => ( <> <SearchHint /> <components.ValueContainer {...props} /> </> ); const DropdownIndicator = () => null; const IndicatorSeparator = () => null; const valueIsPerformer = ( arg?: SceneResult | PerformerResult, ): arg is PerformerResult => arg?.__typename === "Performer"; const formatOptionLabel = ({ label, sublabel, value }: SearchResult) => ( <div className="d-flex"> {valueIsPerformer(value) && ( <Thumbnail image={getImage(value.images, "portrait")} className="SearchField-thumb" alt={value.name} size={300} orientation="portrait" /> )} <div> <div className="search-value"> {valueIsPerformer(value) && <GenderIcon gender={value.gender} />} {value?.deleted ? <del>{label}</del> : label} </div> <div className="search-subvalue">{sublabel}</div> </div> </div> ); const SearchField: FC<SearchFieldProps> = ({ onClick, onClickPerformer, searchType = SearchType.Performer, excludeIDs = [], nav = false, placeholder, showAllLink = false, autoFocus = false, studioId, }) => { const client = useApolloClient(); const navigate = useNavigate(); const [selectedValue, setSelected] = useState(null); const searchTerm = useRef(""); const selectRef = useRef<SelectInstance<SearchResult, false, GroupBase<SearchResult>>>(null); const handleSearch = async (term: string) => { if (term) { const { data } = await client.query< SearchPerformersQuery | SearchAllQuery >({ query: searchType === SearchType.Performer ? SearchPerformersGQL : SearchAllGQL, variables: { term, ...(searchType === SearchType.Performer && studioId ? { studioId, hasStudioId: true } : {}), }, fetchPolicy: "network-only", }); if (!data) return []; return handleResult(data, excludeIDs, showAllLink, studioId); } return []; }; const debouncedLoadOptions = debounce(handleSearch, 400); const handleLoad = (term: string) => { searchTerm.current = term; return debouncedLoadOptions(term); }; const handleChange = (result: OnChangeValue<SearchResult, false>) => { if (result?.type === "ALL") return navigate(`/search?q=${encodeURIComponent(searchTerm.current)}`); if (result?.value) { if (valueIsPerformer(result.value)) onClickPerformer?.(result.value); onClick?.(result.value); if (nav) navigate(`/${result.type}s/${result.value.id}`); } setSelected(null); }; const handleKeyDown = (e: KeyboardEvent<HTMLElement>) => { if (e.key === "Enter" && searchTerm.current && showAllLink) { navigate(`/search?q=${encodeURIComponent(searchTerm.current)}`); selectRef?.current?.blur(); } }; return ( <div className="SearchField"> <Async autoFocus={autoFocus} classNamePrefix="react-select" value={selectedValue} loadOptions={handleLoad} onChange={handleChange} onKeyDown={handleKeyDown} ref={selectRef} placeholder={ placeholder ?? (searchType === SearchType.Performer ? "Search for performer..." : "Search for performer or scene...") } formatOptionLabel={formatOptionLabel} components={{ DropdownIndicator, IndicatorSeparator, ValueContainer, Input: SearchInput, }} noOptionsMessage={({ inputValue }) => inputValue === "" ? null : `No result found for "${inputValue}"` } /> </div> ); }; export default SearchField; ================================================ FILE: frontend/src/components/searchField/handleResult.ts ================================================ import type { SearchAllQuery, SearchPerformersQuery } from "src/graphql"; import { filterData, formatDisambiguation } from "src/utils"; type SceneAllResult = NonNullable< SearchAllQuery["searchScenes"]["scenes"][number] >; type PerformerAllResult = NonNullable< SearchAllQuery["searchPerformers"]["performers"][number] >; type PerformerOnlyResult = NonNullable< SearchPerformersQuery["searchPerformers"]["performers"][number] >; export type PerformerResult = PerformerAllResult | PerformerOnlyResult; export type SceneResult = SceneAllResult; export interface SearchGroup { label: string; options: SearchResult[]; } export interface SearchResult { type: string; value?: SceneResult | PerformerResult; label?: string; sublabel?: string; } interface PerformerSearchResult extends SearchResult { studioSceneCount: number; } const resultIsSearchAll = ( result: SearchAllQuery | SearchPerformersQuery, ): result is SearchAllQuery => (result as SearchAllQuery).searchScenes !== undefined; function formatPerformerLabel(performer: PerformerResult): string { return `${performer.name}${formatDisambiguation(performer)}`; } function formatPerformerSublabel( performer: PerformerResult, studioSceneCount?: number, ): string { const parts: (string | null)[] = []; if (studioSceneCount && studioSceneCount > 0) { parts.push( `${studioSceneCount} scene${studioSceneCount !== 1 ? "s" : ""} for network`, ); } if (performer.birth_date) { parts.push(`Born: ${performer.birth_date}`); } if (performer.aliases.length) { parts.push(`AKA: ${performer.aliases.join(", ")}`); } return parts.filter(Boolean).join(", "); } function getStudioSceneCount(performer: PerformerOnlyResult): number { if ("studios" in performer && performer.studios?.length) { return performer.studios.reduce((sum, s) => sum + s.scene_count, 0); } return 0; } function formatSceneLabel(scene: SceneResult): string { return `${scene.title}${scene.release_date ? ` (${scene.release_date})` : ""}`; } function formatSceneSublabel(scene: SceneResult): string { return filterData([ scene.studio?.name, scene.code ? `Code ${scene.code}` : null, scene.performers ? scene.performers.map((p) => p.as || p.performer.name).join(", ") : null, ]).join(" • "); } function handleSearchAllResult( result: SearchAllQuery, excludeIDs: string[], ): { performers: SearchResult[]; scenes: SearchResult[] } { const performers = (result.searchPerformers.performers ?? []) .filter((p): p is PerformerAllResult => p !== null) .filter((performer) => !excludeIDs.includes(performer.id)) .map( (performer): SearchResult => ({ type: "performer", value: performer, label: formatPerformerLabel(performer), sublabel: formatPerformerSublabel(performer), }), ); const scenes = (result.searchScenes.scenes ?? []) .filter((s): s is SceneResult => s !== null) .filter((scene) => !excludeIDs.includes(scene.id)) .map( (scene): SearchResult => ({ type: "scene", value: scene, label: formatSceneLabel(scene), sublabel: formatSceneSublabel(scene), }), ); return { performers, scenes }; } function handlePerformerSearchResult( result: SearchPerformersQuery, excludeIDs: string[], studioId?: string, ): PerformerSearchResult[] { return (result.searchPerformers.performers ?? []) .filter((p): p is PerformerOnlyResult => p !== null) .filter((performer) => !excludeIDs.includes(performer.id)) .map((performer): PerformerSearchResult => { const studioSceneCount = studioId ? getStudioSceneCount(performer) : 0; return { type: "performer", value: performer, label: formatPerformerLabel(performer), sublabel: formatPerformerSublabel(performer, studioSceneCount), studioSceneCount, }; }); } function groupPerformersByStudio( performers: PerformerSearchResult[], ): SearchGroup[] { const studioPerformers = performers.filter((p) => p.studioSceneCount > 0); const otherPerformers = performers.filter((p) => p.studioSceneCount === 0); const groups: SearchGroup[] = []; if (studioPerformers.length > 0) { groups.push({ label: "Studio Performers", options: studioPerformers }); } if (otherPerformers.length > 0) { const label = studioPerformers.length > 0 ? "Other Performers" : "Performers"; groups.push({ label, options: otherPerformers }); } return groups; } function createPerformerGroups(performers: SearchResult[]): SearchGroup[] { if (performers.length === 0) return []; return [{ label: "Performers", options: performers }]; } function createSceneGroups(scenes: SearchResult[]): SearchGroup[] { if (scenes.length === 0) return []; return [{ label: "Scenes", options: scenes }]; } export function handleResult( result: SearchAllQuery | SearchPerformersQuery, excludeIDs: string[], showAllLink: boolean, studioId?: string, ): (SearchGroup | SearchResult)[] { let performerGroups: SearchGroup[]; let sceneGroups: SearchGroup[]; if (resultIsSearchAll(result)) { const { performers, scenes } = handleSearchAllResult(result, excludeIDs); performerGroups = createPerformerGroups(performers); sceneGroups = createSceneGroups(scenes); } else { const performers = handlePerformerSearchResult( result, excludeIDs, studioId, ); performerGroups = studioId ? groupPerformersByStudio(performers) : createPerformerGroups(performers); sceneGroups = []; } const hasResults = performerGroups.length > 0 || sceneGroups.length > 0; const showAll: SearchResult[] = showAllLink && hasResults ? [{ type: "ALL", label: "Show all results" }] : []; return [...showAll, ...performerGroups, ...sceneGroups]; } ================================================ FILE: frontend/src/components/searchField/index.ts ================================================ export { default } from "./SearchField"; export * from "./SearchField"; ================================================ FILE: frontend/src/components/searchField/styles.scss ================================================ .SearchField { width: 400px; z-index: 5; .search-value { font-size: 14px; font-weight: 500; } .search-subvalue { font-size: 12px; } &-thumb { aspect-ratio: 2/3; height: 4rem; width: auto; object-fit: cover; margin-right: 0.5rem; } .react-select__menu-list { max-height: 600px; } } ================================================ FILE: frontend/src/components/studioSelect/StudioSelect.tsx ================================================ import type { FC } from "react"; import { components } from "react-select"; import Async from "react-select/async"; import { useApolloClient } from "@apollo/client/react"; import debounce from "p-debounce"; import { SearchHint, SearchInput } from "src/components/fragments"; import StudiosGQL from "src/graphql/queries/Studios.gql"; import StudioGQL from "src/graphql/queries/Studio.gql"; import { SortDirectionEnum, StudioSortEnum, type StudiosQuery, type StudiosQueryVariables, type StudioQuery, type StudioQueryVariables, } from "src/graphql"; import { isUUID } from "src/utils"; type Studio = NonNullable<StudioQuery["findStudio"]>; type StudioParent = { id: string; name: string } | null; type StudioSlim = Pick<Studio, "id" | "name"> & { parent?: StudioParent }; interface IOptionType { value: string; label: string; sublabel: string | undefined; parent: StudioParent; } interface StudioSelectProps { initialStudio?: StudioSlim | null; excludeStudio?: string; onChange: (studio: StudioSlim | null) => void; onBlur?: React.FocusEventHandler; networkSelect?: boolean; isClearable?: boolean; } const ValueContainer: typeof components.ValueContainer = (props) => ( <> <SearchHint /> <components.ValueContainer {...props} /> </> ); const CLASSNAME = "StudioSelect"; const CLASSNAME_SELECT = `${CLASSNAME}-select`; const StudioSelect: FC<StudioSelectProps> = ({ initialStudio, excludeStudio, onChange, onBlur, networkSelect = false, isClearable = false, }) => { const client = useApolloClient(); const fetchStudios = async (term: string): Promise<IOptionType[]> => { const value = term.trim(); if (isUUID(value)) { if (value === excludeStudio) { return []; } const { data } = await client.query<StudioQuery, StudioQueryVariables>({ query: StudioGQL, variables: { id: value }, }); const studio = data?.findStudio; if (!studio || (networkSelect && studio.parent !== null)) { return []; } return [ { value: studio.id, label: studio.name, sublabel: studio.parent?.name, parent: studio.parent ?? null, }, ]; } const { data } = await client.query<StudiosQuery, StudiosQueryVariables>({ query: StudiosGQL, variables: { input: { name: term, has_parent: networkSelect ? false : undefined, page: 1, per_page: 25, sort: StudioSortEnum.NAME, direction: SortDirectionEnum.ASC, }, }, }); if (!data) return []; return data?.queryStudios?.studios .map((s) => ({ value: s.id, label: s.name, sublabel: s.parent?.name, parent: s.parent ?? null, })) .filter((s) => s.value !== excludeStudio); }; const debouncedLoad = debounce(fetchStudios, 200); const defaultValue = initialStudio ? { value: initialStudio.id, label: initialStudio.name, sublabel: initialStudio.parent?.name, parent: initialStudio.parent ?? null, } : undefined; const formatStudioName = (opt: IOptionType) => ( <> <span>{opt.label}</span> {opt.sublabel && ( <small className="bullet-separator parent-studio">{opt.sublabel}</small> )} </> ); return ( <div className={CLASSNAME}> <Async isMulti={false} classNamePrefix="react-select" className={`react-select ${CLASSNAME_SELECT}`} onChange={(s) => onChange(s ? { id: s.value, name: s.label, parent: s.parent } : null) } onBlur={onBlur} defaultValue={defaultValue} loadOptions={debouncedLoad} placeholder="Search for studio" noOptionsMessage={({ inputValue }) => inputValue === "" ? null : `No studios found for "${inputValue}"` } isClearable={isClearable} formatOptionLabel={formatStudioName} components={{ ValueContainer, Input: SearchInput, }} /> </div> ); }; export default StudioSelect; ================================================ FILE: frontend/src/components/studioSelect/index.ts ================================================ export { default } from "./StudioSelect"; ================================================ FILE: frontend/src/components/studioSelect/styles.scss ================================================ .StudioSelect { .parent-studio { color: $text-muted; } .react-select__value-container { .parent-studio { color: rgba($black, 0.5); } } } ================================================ FILE: frontend/src/components/tagFilter/TagFilter.tsx ================================================ import type { FC } from "react"; import Async from "react-select/async"; import type { OnChangeValue, MenuPlacement } from "react-select"; import { useApolloClient } from "@apollo/client/react"; import debounce from "p-debounce"; import SearchTagsGQL from "src/graphql/queries/SearchTags.gql"; import { type SearchTagsQuery, type SearchTagsQueryVariables, useTag, } from "src/graphql"; type Tag = NonNullable<SearchTagsQuery["query"][number]>; interface TagFilterProps { tag: string; onChange: (tag: Tag | undefined) => void; excludeTags?: string[]; menuPlacement?: MenuPlacement; allowDeleted?: boolean; } interface SearchResult { value: Tag; label: string; sublabel: string; } const CLASSNAME = "TagFilter"; const CLASSNAME_SELECT = `${CLASSNAME}-select`; const TagFilter: FC<TagFilterProps> = ({ tag: tagId, onChange, excludeTags = [], menuPlacement = "auto", allowDeleted = false, }) => { const client = useApolloClient(); const { data: tagData } = useTag({ id: tagId }, !tagId); const selectedTag = tagData?.findTag; const handleChange = (result: OnChangeValue<SearchResult, false>) => { onChange(result?.value); }; const handleSearch = async (term: string) => { const { data } = await client.query< SearchTagsQuery, SearchTagsQueryVariables >({ query: SearchTagsGQL, variables: { term, limit: 25, }, }); const { exact, query } = data ?? {}; const exactResult = exact && (allowDeleted || !exact.deleted) && !excludeTags.includes(exact.id) ? { label: exact.name, value: exact, sublabel: exact.description ?? "", } : undefined; const queryResult = query ?.filter( (tag) => !excludeTags.includes(tag.id) && (allowDeleted || !tag.deleted) && tag.id !== exact?.id, ) .map((tag) => ({ label: tag.name, value: tag, sublabel: tag.description ?? "", })); return [ ...(exactResult ? [ { label: exactResult.label.toLowerCase() === term.toLowerCase() ? "Exact Match" : "Alias Match", options: [exactResult], }, ] : []), ...(queryResult ? [{ label: "Tags", options: queryResult }] : []), ]; }; const debouncedLoadOptions = debounce(handleSearch, 400); const formatOptionLabel = ({ label, sublabel, value }: SearchResult) => { return ( <div title={value.aliases.map((a) => `\u{2022} ${a}`).join("\n")}> <div className={`${CLASSNAME_SELECT}-value`}> {value.deleted ? <del>{label}</del> : label} </div> <div className={`${CLASSNAME_SELECT}-subvalue`}>{sublabel}</div> </div> ); }; return ( <Async classNamePrefix="react-select" className={`react-select ${CLASSNAME_SELECT}`} onChange={handleChange} loadOptions={debouncedLoadOptions} placeholder="Filter by tag" noOptionsMessage={({ inputValue }) => inputValue === "" ? null : `No tags found for "${inputValue}"` } value={ selectedTag && { label: selectedTag.name, value: selectedTag, sublabel: "", } } isClearable menuPlacement={menuPlacement} formatOptionLabel={formatOptionLabel} /> ); }; export default TagFilter; ================================================ FILE: frontend/src/components/tagFilter/index.ts ================================================ import TagFilter from "./TagFilter"; export default TagFilter; ================================================ FILE: frontend/src/components/tagFilter/styles.scss ================================================ .TagFilter { &-select { display: inline-block; margin-right: 0.5rem; width: 14rem; .react-select__menu { width: 400px; } &-value { font-size: 14px; font-weight: 500; } &-subvalue { font-size: 12px; color: $text-muted; } } } ================================================ FILE: frontend/src/components/tagSelect/TagSelect.tsx ================================================ import { type FC, useState } from "react"; import Async from "react-select/async"; import type { OnChangeValue, MenuPlacement } from "react-select"; import { useApolloClient } from "@apollo/client/react"; import debounce from "p-debounce"; import SearchTagsGQL from "src/graphql/queries/SearchTags.gql"; import type { SearchTagsQuery, SearchTagsQueryVariables } from "src/graphql"; import { SearchInput, TagLink } from "src/components/fragments"; import { tagHref } from "src/utils/route"; import { compareByName } from "src/utils"; type Tag = NonNullable<SearchTagsQuery["query"][number]>; type TagSlim = { id: string; name: string; description?: string | null | undefined; aliases: string[]; }; interface TagSelectProps { tags?: TagSlim[]; onChange: (tags: TagSlim[]) => void; message?: string; excludeTags?: string[]; menuPlacement?: MenuPlacement; allowDeleted?: boolean; } interface SearchResult { value: Tag; label: string; sublabel: string; } const CLASSNAME = "TagSelect"; const CLASSNAME_LIST = `${CLASSNAME}-list`; const CLASSNAME_SELECT = `${CLASSNAME}-select`; const CLASSNAME_CONTAINER = `${CLASSNAME}-container`; const TagSelect: FC<TagSelectProps> = ({ tags: initialTags = [], onChange, message = "Add tag:", excludeTags = [], menuPlacement = "auto", allowDeleted = false, }) => { const client = useApolloClient(); const [tags, setTags] = useState(initialTags); const excluded = [...excludeTags, ...tags.map((t) => t.id)]; const handleChange = (result: OnChangeValue<SearchResult, false>) => { if (result?.value) { const newTags = [...tags, result.value]; setTags(newTags); onChange(newTags); } }; const removeTag = (id: string) => { const newTags = tags.filter((tag) => tag.id !== id); setTags(newTags); onChange(newTags); }; const tagList = [...(tags ?? [])] .sort(compareByName) .map((tag) => ( <TagLink title={tag.name} description={tag.description} link={tagHref(tag)} onRemove={() => removeTag(tag.id)} key={tag.id} disabled /> )); const handleSearch = async (term: string) => { const { data } = await client.query< SearchTagsQuery, SearchTagsQueryVariables >({ query: SearchTagsGQL, variables: { term, limit: 25, }, }); const { exact, query } = data ?? {}; const exactResult = exact && !excluded.includes(exact.id) && (allowDeleted || !exact.deleted) ? { label: exact.name, value: exact, sublabel: exact.description ?? "", } : undefined; const queryResult = query ?.filter( (tag) => !excluded.includes(tag.id) && (allowDeleted || !tag.deleted) && tag.id !== exact?.id, ) .map((tag) => ({ label: tag.name, value: tag, sublabel: tag.description ?? "", })); return [ ...(exactResult ? [ { label: exactResult.label.toLowerCase() === term.toLowerCase() ? "Exact Match" : "Alias Match", options: [exactResult], }, ] : []), ...(queryResult ? [{ label: "Tags", options: queryResult }] : []), ]; }; const debouncedLoadOptions = debounce(handleSearch, 400); const formatOptionLabel = ({ label, sublabel, value }: SearchResult) => { return ( <div title={value.aliases.map((a) => `\u{2022} ${a}`).join("\n")}> <div className={`${CLASSNAME_SELECT}-value`}> {value.deleted ? <del>{label}</del> : label} </div> <div className={`${CLASSNAME_SELECT}-subvalue`}>{sublabel}</div> </div> ); }; return ( <div className={CLASSNAME}> <div className={CLASSNAME_LIST}>{tagList}</div> <div className={CLASSNAME_CONTAINER}> <span>{message}</span> <Async isMulti={false} classNamePrefix="react-select" className={`react-select ${CLASSNAME_SELECT}`} onChange={handleChange} loadOptions={debouncedLoadOptions} placeholder="Search for tag" noOptionsMessage={({ inputValue }) => inputValue === "" ? null : `No tags found for "${inputValue}"` } menuPlacement={menuPlacement} controlShouldRenderValue={false} formatOptionLabel={formatOptionLabel} components={{ Input: SearchInput }} /> </div> </div> ); }; export default TagSelect; ================================================ FILE: frontend/src/components/tagSelect/index.ts ================================================ import TagSelect from "./TagSelect"; export default TagSelect; ================================================ FILE: frontend/src/components/tagSelect/styles.scss ================================================ .TagSelect { margin-top: 0.5rem; &-list { margin-bottom: 1rem; } &-container { display: flex; } &-select { display: inline-block; margin-left: auto; width: 25rem; &-value { font-size: 14px; font-weight: 500; } &-subvalue { font-size: 12px; color: $text-muted; } } } ================================================ FILE: frontend/src/components/title/Title.tsx ================================================ import type { FC } from "react"; import { Helmet } from "react-helmet"; // Title is only injected in production, so default to Stash-Box in dev const INSTANCE_TITLE = document.title === "{{.}}" ? "Stash-Box" : document.title; interface Props { page?: string; } const Title: FC<Props> = ({ page }) => ( <Helmet> <title>{page ? `${page} | ${INSTANCE_TITLE}` : INSTANCE_TITLE} ); export default Title; ================================================ FILE: frontend/src/components/title/index.ts ================================================ export { default } from "./Title"; ================================================ FILE: frontend/src/components/urlChangeRow/URLChangeRow.tsx ================================================ import type { FC } from "react"; import { Col, Row } from "react-bootstrap"; import { SiteLink } from "src/components/fragments"; const CLASSNAME = "URLChangeRow"; export interface URL { url: string; site: { id: string; name: string; icon: string; }; } const URLChanges: FC<{ urls: URL[] }> = ({ urls }) => (
); interface URLChangeRowProps { newURLs?: URL[] | null; oldURLs?: URL[] | null; showDiff?: boolean; } const URLChangeRow: FC = ({ newURLs, oldURLs, showDiff }) => (newURLs ?? []).length > 0 || (oldURLs ?? []).length > 0 ? ( Links {showDiff && ( {(oldURLs ?? []).length > 0 && ( <>
Removed
)} )} {(newURLs ?? []).length > 0 && ( <> {showDiff &&
Added
} )}
) : null; export default URLChangeRow; ================================================ FILE: frontend/src/components/urlChangeRow/index.ts ================================================ export { default } from "./URLChangeRow"; export type { URL } from "./URLChangeRow"; ================================================ FILE: frontend/src/components/urlInput/index.ts ================================================ import URLInput from "./urlInput"; export default URLInput; ================================================ FILE: frontend/src/components/urlInput/styles.scss ================================================ .URLInput { width: 100%; ul { list-style-type: none; padding-left: 0; } li { margin-bottom: 0.5rem; } .input-group { flex-wrap: nowrap; } } ================================================ FILE: frontend/src/components/urlInput/urlInput.tsx ================================================ import { type FC, useRef, useState } from "react"; import { Button, Form, InputGroup } from "react-bootstrap"; import { Icon } from "src/components/fragments"; import type { FieldError, Merge, FieldErrorsImpl } from "react-hook-form"; import { useFieldArray } from "react-hook-form"; import type { Lens } from "@hookform/lenses"; import { faExternalLinkAlt } from "@fortawesome/free-solid-svg-icons"; import { useSites, type ValidSiteTypeEnum, type SiteQuery } from "src/graphql"; import { cleanURL } from "src/utils"; type Site = NonNullable; const CLASSNAME = "URLInput"; export type URLItem = { url: string; site: { id: string; name: string; icon: string; }; }; type ErrorsType = Merge< FieldError, (Merge> | undefined)[] >; interface URLInputProps { lens: Lens; type: ValidSiteTypeEnum; errors?: ErrorsType; } const URLInput: FC = ({ lens, type, errors }) => { const interop = lens.interop(); const { fields: urls, append, remove, } = useFieldArray({ control: interop.control, name: interop.name, keyName: "key", }); const [newURL, setNewURL] = useState(""); const [selectedSite, setSelectedSite] = useState(); const selectRef = useRef(null); const inputRef = useRef(null); const { data, loading } = useSites(); if (loading) return null; const sites = (data?.querySites.sites ?? []).filter((s) => s.valid_types.includes(type), ); const handleAdd = () => { if (!newURL || !selectedSite) return; const cleanedURL = cleanURL(selectedSite?.regex, newURL); const url = cleanedURL ?? newURL; if (!urls.some((u) => u.url === url)) append({ url, site: selectedSite, }); if (selectRef.current) selectRef.current.value = ""; if (inputRef.current) inputRef.current.value = ""; setSelectedSite(undefined); setNewURL(""); }; const handleInput = (url: string) => { if (!inputRef.current || !selectRef.current) return; const site = sites.find((s) => s.regex && new RegExp(s.regex).test(url)); if (site && selectedSite?.id !== site.id) { setSelectedSite(site); selectRef.current.value = site.id; } else if (url && !site && selectedSite?.regex) { setSelectedSite(undefined); selectRef.current.value = ""; } if (site?.regex && url) { const updatedURL = cleanURL(site.regex, url); if (updatedURL) { inputRef.current.value = updatedURL; return true; } } return false; }; const handlePaste = (e: React.ClipboardEvent) => { const match = handleInput(e.clipboardData.getData("text/plain")); if (match) { e.preventDefault(); setNewURL(e.currentTarget.value); } }; const handleSiteSelect = (e: React.ChangeEvent) => { const site = sites.find((s) => s.id === e.currentTarget.value); if (site) setSelectedSite(site); }; return (
    {urls.map((u, i) => (
  • {u.site.name} {u.url} {errors?.[i]?.url && (
    {errors?.[i]?.url?.message}
    )}
  • ))}
Add new link {sites.length === 0 ? ( ) : ( sites.map((s) => ( )) )} handleInput(e.currentTarget.value)} placeholder="URL" onChange={(e) => setNewURL(e.currentTarget.value)} onPaste={handlePaste} className="w-50" />
); }; export default URLInput; ================================================ FILE: frontend/src/constants/enums.ts ================================================ import { BreastTypeEnum, EthnicityEnum, EthnicityFilterEnum, EyeColorEnum, HairColorEnum, GenderEnum, GenderFilterEnum, OperationEnum, TargetTypeEnum, UserVotedFilterEnum, VoteStatusEnum, VoteTypeEnum, } from "src/graphql"; type EnumDictionary = { [K in T]: U; }; export const BreastTypes: EnumDictionary = { [BreastTypeEnum.NA]: "N/A", [BreastTypeEnum.FAKE]: "Augmented", [BreastTypeEnum.NATURAL]: "Natural", }; export const EthnicityTypes: EnumDictionary = { [EthnicityEnum.ASIAN]: "Asian", [EthnicityEnum.BLACK]: "Black", [EthnicityEnum.LATIN]: "Latin", [EthnicityEnum.MIXED]: "Mixed", [EthnicityEnum.OTHER]: "Other", [EthnicityEnum.INDIAN]: "Indian", [EthnicityEnum.CAUCASIAN]: "Caucasian", [EthnicityEnum.MIDDLE_EASTERN]: "Middle Eastern", }; export const EthnicityFilterTypes: EnumDictionary = { ...EthnicityTypes, [EthnicityFilterEnum.UNKNOWN]: "Unknown Ethnicity", }; export const EyeColorTypes: EnumDictionary = { [EyeColorEnum.BLUE]: "Blue", [EyeColorEnum.BROWN]: "Brown", [EyeColorEnum.GREEN]: "Green", [EyeColorEnum.GREY]: "Grey", [EyeColorEnum.HAZEL]: "Hazel", [EyeColorEnum.RED]: "Red", }; export const HairColorTypes: EnumDictionary = { [HairColorEnum.AUBURN]: "Auburn", [HairColorEnum.BALD]: "Bald", [HairColorEnum.BLACK]: "Black", [HairColorEnum.BLONDE]: "Blond", [HairColorEnum.BRUNETTE]: "Brown", [HairColorEnum.GREY]: "Grey", [HairColorEnum.OTHER]: "Other", [HairColorEnum.RED]: "Red", [HairColorEnum.VARIOUS]: "Various", [HairColorEnum.WHITE]: "White", }; export const GenderTypes: EnumDictionary = { [GenderEnum.MALE]: "Male", [GenderEnum.FEMALE]: "Female", [GenderEnum.INTERSEX]: "Intersex", [GenderEnum.NON_BINARY]: "Non-binary", [GenderEnum.TRANSGENDER_MALE]: "Transmale", [GenderEnum.TRANSGENDER_FEMALE]: "Transfemale", }; export const GenderFilterTypes: EnumDictionary = { ...GenderTypes, [GenderFilterEnum.UNKNOWN]: "Unknown Gender", }; export const EditOperationTypes: EnumDictionary = { [OperationEnum.MERGE]: "Merge", [OperationEnum.CREATE]: "Create", [OperationEnum.MODIFY]: "Modify", [OperationEnum.DESTROY]: "Destroy", }; export const EditTargetTypes: EnumDictionary = { [TargetTypeEnum.TAG]: "Tag", [TargetTypeEnum.PERFORMER]: "Performer", [TargetTypeEnum.SCENE]: "Scene", [TargetTypeEnum.STUDIO]: "Studio", }; export const EditStatusTypes: EnumDictionary = { [VoteStatusEnum.PENDING]: "Pending", [VoteStatusEnum.IMMEDIATE_ACCEPTED]: "Admin Accepted", [VoteStatusEnum.IMMEDIATE_REJECTED]: "Admin Rejected", [VoteStatusEnum.ACCEPTED]: "Accepted", [VoteStatusEnum.REJECTED]: "Rejected", [VoteStatusEnum.FAILED]: "Failed", [VoteStatusEnum.CANCELED]: "Cancelled", }; export const VoteTypes: EnumDictionary = { [VoteTypeEnum.ACCEPT]: "Yes", [VoteTypeEnum.IMMEDIATE_ACCEPT]: "Admin Accept", [VoteTypeEnum.IMMEDIATE_REJECT]: "Admin Reject", [VoteTypeEnum.ABSTAIN]: "Abstain", [VoteTypeEnum.REJECT]: "No", }; export const UserVotedFilterTypes: EnumDictionary = { [UserVotedFilterEnum.NOT_VOTED]: "Not Yet Voted", [UserVotedFilterEnum.ACCEPT]: "Yes", [UserVotedFilterEnum.ABSTAIN]: "Abstain", [UserVotedFilterEnum.REJECT]: "No", }; ================================================ FILE: frontend/src/constants/index.ts ================================================ export * from "./enums"; export * from "./route"; ================================================ FILE: frontend/src/constants/route.ts ================================================ export const ROUTE_HOME = "/"; export const ROUTE_LOGIN = "/login"; export const ROUTE_LOGOUT = "/logout"; export const ROUTE_USERS = "/users"; export const ROUTE_USER_ADD = "/users/add"; export const ROUTE_USER = "/users/:name"; export const ROUTE_USER_EDIT = "/users/:name/edit"; export const ROUTE_USER_PASSWORD = "/users/change-password"; export const ROUTE_USER_EDITS = "/users/:name/edits"; export const ROUTE_USER_MY_FINGERPRINTS = "/users/fingerprints"; export const ROUTE_PERFORMER = "/performers/:id"; export const ROUTE_PERFORMER_ADD = "/performers/add"; export const ROUTE_PERFORMER_EDIT = "/performers/:id/edit"; export const ROUTE_PERFORMER_MERGE = "/performers/:id/merge"; export const ROUTE_PERFORMER_DELETE = "/performers/:id/delete"; export const ROUTE_PERFORMERS = "/performers"; export const ROUTE_SCENE = "/scenes/:id"; export const ROUTE_SCENE_ADD = "/scenes/add"; export const ROUTE_SCENE_EDIT = "/scenes/:id/edit"; export const ROUTE_SCENE_DELETE = "/scenes/:id/delete"; export const ROUTE_SCENES = "/scenes"; export const ROUTE_STUDIO = "/studios/:id"; export const ROUTE_STUDIO_ADD = "/studios/add"; export const ROUTE_STUDIO_EDIT = "/studios/:id/edit"; export const ROUTE_STUDIO_DELETE = "/studios/:id/delete"; export const ROUTE_STUDIOS = "/studios"; export const ROUTE_TAG = "/tags/:id"; export const ROUTE_TAG_ADD = "/tags/add"; export const ROUTE_TAG_MERGE = "/tags/:id/merge"; export const ROUTE_TAG_EDIT = "/tags/:id/edit"; export const ROUTE_TAG_DELETE = "/tags/:id/delete"; export const ROUTE_TAGS = "/tags"; export const ROUTE_CATEGORY = "/categories/:id"; export const ROUTE_CATEGORY_ADD = "/categories/add"; export const ROUTE_CATEGORY_EDIT = "/categories/:id/edit"; export const ROUTE_CATEGORIES = "/categories"; export const ROUTE_EDITS = "/edits"; export const ROUTE_EDIT = "/edits/:id"; export const ROUTE_EDIT_UPDATE = "/edits/:id/update"; export const ROUTE_EDIT_AMEND = "/edits/:id/amend"; export const ROUTE_REGISTER = "/register"; export const ROUTE_ACTIVATE = "/activate"; export const ROUTE_FORGOT_PASSWORD = "/forgot-password"; export const ROUTE_RESET_PASSWORD = "/reset-password"; export const ROUTE_CONFIRM_EMAIL = "/users/confirm-email"; export const ROUTE_CHANGE_EMAIL = "/users/change-email"; export const ROUTE_SEARCH = "/search"; export const ROUTE_VERSION = "/version"; export const ROUTE_SITE = "/sites/:id"; export const ROUTE_SITE_ADD = "/sites/add"; export const ROUTE_SITE_EDIT = "/sites/:id/edit"; export const ROUTE_SITES = "/sites"; export const ROUTE_DRAFT = "/drafts/:id"; export const ROUTE_DRAFTS = "/drafts"; export const ROUTE_NOTIFICATIONS = "/notifications"; export const ROUTE_NOTIFICATION_SUBSCRIPTIONS = "/users/:name/notifications"; export const ROUTE_AUDITS = "/audits"; ================================================ FILE: frontend/src/context.tsx ================================================ import { createContext, useContext } from "react"; import type { RoleEnum } from "src/graphql"; export interface User { id: string; name: string; roles?: RoleEnum[] | null; } export type ContextType = { authenticated: boolean; user?: User; }; const AuthContext = createContext({ authenticated: false, }); export const useAuthContext = () => useContext(AuthContext); export default AuthContext; ================================================ FILE: frontend/src/graphql/fragments/CommentFragment.gql ================================================ fragment CommentFragment on EditComment { id user { id name } date comment } ================================================ FILE: frontend/src/graphql/fragments/EditFragment.gql ================================================ #import "../fragments/PerformerFragment.gql" #import "../fragments/StudioFragment.gql" #import "../fragments/ImageFragment.gql" #import "../fragments/SceneFragment.gql" #import "../fragments/TagFragment.gql" #import "../fragments/CommentFragment.gql" #import "../fragments/URLFragment.gql" #import "../fragments/FingerprintFragment.gql" fragment EditFragment on Edit { id target_type operation status bot applied created updated closed expires update_count updatable vote_count destructive comments { ...CommentFragment } votes { user { id name } date vote } user { id name } target { ... on Tag { ...TagFragment } ... on Performer { ...PerformerFragment } ... on Studio { ...StudioFragment } ... on Scene { ...SceneFragment } } details { ... on TagEdit { name description added_aliases removed_aliases category { id name } } ... on PerformerEdit { name disambiguation added_aliases removed_aliases gender added_urls { ...URLFragment } removed_urls { ...URLFragment } birthdate deathdate ethnicity country eye_color hair_color height cup_size band_size waist_size hip_size breast_type career_start_year career_end_year added_tattoos { location description } removed_tattoos { location description } added_piercings { location description } removed_piercings { location description } added_images { ...ImageFragment } removed_images { ...ImageFragment } draft_id } ... on StudioEdit { name added_aliases removed_aliases added_urls { ...URLFragment } removed_urls { ...URLFragment } parent { ...StudioFragment } added_images { ...ImageFragment } removed_images { ...ImageFragment } } ... on SceneEdit { title details added_urls { ...URLFragment } removed_urls { ...URLFragment } date production_date studio { ...StudioFragment } added_performers { performer { ...PerformerFragment } as } removed_performers { performer { ...PerformerFragment } as } added_tags { ...TagFragment } removed_tags { ...TagFragment } added_images { ...ImageFragment } removed_images { ...ImageFragment } added_fingerprints { ...FingerprintFragment } removed_fingerprints { ...FingerprintFragment } duration director code draft_id } } old_details { ... on TagEdit { name description category { id name } } ... on PerformerEdit { name disambiguation gender birthdate deathdate ethnicity country eye_color hair_color height cup_size band_size waist_size hip_size breast_type career_start_year career_end_year } ... on StudioEdit { name parent { ...StudioFragment } } ... on SceneEdit { title details added_urls { ...URLFragment } removed_urls { ...URLFragment } date production_date studio { ...StudioFragment } added_performers { performer { ...PerformerFragment } as } removed_performers { performer { ...PerformerFragment } as } added_tags { ...TagFragment } removed_tags { ...TagFragment } added_images { ...ImageFragment } removed_images { ...ImageFragment } added_fingerprints { ...FingerprintFragment } removed_fingerprints { ...FingerprintFragment } duration director code } } merge_sources { ... on Tag { ...TagFragment } ... on Performer { ...PerformerFragment } ... on Studio { ...StudioFragment } ... on Scene { ...SceneFragment } } options { set_modify_aliases set_merge_aliases } } ================================================ FILE: frontend/src/graphql/fragments/FingerprintFragment.gql ================================================ fragment FingerprintFragment on Fingerprint { hash algorithm duration } ================================================ FILE: frontend/src/graphql/fragments/ImageFragment.gql ================================================ fragment ImageFragment on Image { id url width height } ================================================ FILE: frontend/src/graphql/fragments/PerformerFragment.gql ================================================ #import "../fragments/ImageFragment.gql" #import "../fragments/URLFragment.gql" fragment PerformerFragment on Performer { id name disambiguation deleted merged_into_id aliases gender birth_date death_date age height hair_color eye_color ethnicity country career_end_year career_start_year breast_type waist_size hip_size band_size cup_size tattoos { location description } piercings { location description } urls { ...URLFragment } images { ...ImageFragment } is_favorite } ================================================ FILE: frontend/src/graphql/fragments/QuerySceneFragment.gql ================================================ #import "../fragments/URLFragment.gql" #import "../fragments/ImageFragment.gql" #import "../fragments/ScenePerformerFragment.gql" fragment QuerySceneFragment on Scene { id release_date title duration urls { ...URLFragment } images { ...ImageFragment } studio { id name } performers { as performer { ...ScenePerformerFragment } } } ================================================ FILE: frontend/src/graphql/fragments/SceneFragment.gql ================================================ #import "../fragments/ImageFragment.gql" #import "../fragments/ScenePerformerFragment.gql" #import "../fragments/URLFragment.gql" fragment SceneFragment on Scene { id release_date production_date title deleted details director code duration urls { ...URLFragment } images { ...ImageFragment } studio { id name parent { id name } } performers { as performer { ...ScenePerformerFragment } } fingerprints { hash algorithm duration submissions reports user_submitted user_reported created updated } tags { id name description aliases } } ================================================ FILE: frontend/src/graphql/fragments/ScenePerformerFragment.gql ================================================ fragment ScenePerformerFragment on Performer { id name disambiguation deleted gender aliases } ================================================ FILE: frontend/src/graphql/fragments/SearchPerformerFragment.gql ================================================ #import "../fragments/ImageFragment.gql" #import "../fragments/URLFragment.gql" fragment SearchPerformerFragment on Performer { id name disambiguation deleted gender aliases country career_start_year career_end_year scene_count birth_date urls { ...URLFragment } images { ...ImageFragment } is_favorite } ================================================ FILE: frontend/src/graphql/fragments/StudioFragment.gql ================================================ #import "../fragments/URLFragment.gql" fragment StudioFragment on Studio { id name aliases parent { id name } urls { ...URLFragment } images { id url height width } deleted is_favorite } ================================================ FILE: frontend/src/graphql/fragments/TagFragment.gql ================================================ fragment TagFragment on Tag { id name description deleted category { id name } aliases } ================================================ FILE: frontend/src/graphql/fragments/URLFragment.gql ================================================ fragment URLFragment on URL { url site { id name icon } } ================================================ FILE: frontend/src/graphql/index.ts ================================================ export * from "./queries"; export * from "./mutations"; export * from "./types"; ================================================ FILE: frontend/src/graphql/mutations/ActivateNewUser.gql ================================================ mutation ActivateNewUser($input: ActivateNewUserInput!) { activateNewUser(input: $input) { id } } ================================================ FILE: frontend/src/graphql/mutations/AddImage.gql ================================================ mutation AddImage($imageData: ImageCreateInput!) { imageCreate(input: $imageData) { id url width height } } ================================================ FILE: frontend/src/graphql/mutations/AddScene.gql ================================================ mutation AddScene($sceneData: SceneCreateInput!) { sceneCreate(input: $sceneData) { id release_date production_date title code details director urls { url site { id name } } studio { id name } performers { performer { name id gender aliases } } fingerprints { hash algorithm duration } tags { id name description } } } ================================================ FILE: frontend/src/graphql/mutations/AddSite.gql ================================================ mutation AddSite($siteData: SiteCreateInput!) { siteCreate(input: $siteData) { id name description url regex valid_types } } ================================================ FILE: frontend/src/graphql/mutations/AddStudio.gql ================================================ mutation AddStudio($studioData: StudioCreateInput!) { studioCreate(input: $studioData) { id name aliases urls { url site { id name } } } } ================================================ FILE: frontend/src/graphql/mutations/AddTagCategory.gql ================================================ mutation AddTagCategory($categoryData: TagCategoryCreateInput!) { tagCategoryCreate(input: $categoryData) { id name description group } } ================================================ FILE: frontend/src/graphql/mutations/AddUser.gql ================================================ mutation AddUser($userData: UserCreateInput!) { userCreate(input: $userData) { id name email roles } } ================================================ FILE: frontend/src/graphql/mutations/AmendEdit.gql ================================================ mutation AmendEdit($input: AmendEditInput!) { amendEdit(input: $input) { ...EditFragment } } ================================================ FILE: frontend/src/graphql/mutations/ApplyEdit.gql ================================================ #import "../fragments/EditFragment.gql" mutation ApplyEdit($input: ApplyEditInput!) { applyEdit(input: $input) { ...EditFragment } } ================================================ FILE: frontend/src/graphql/mutations/CancelEdit.gql ================================================ mutation CancelEdit($input: CancelEditInput!) { cancelEdit(input: $input) { id target_type operation status applied created user { id name } target { ... on Tag { id name description deleted } } details { ... on TagEdit { name description added_aliases removed_aliases } } merge_sources { ... on Tag { id name description } } } } ================================================ FILE: frontend/src/graphql/mutations/ChangePassword.gql ================================================ mutation ChangePassword($userData: UserChangePasswordInput!) { changePassword(input: $userData) } ================================================ FILE: frontend/src/graphql/mutations/ConfirmChangeEmail.gql ================================================ mutation ConfirmChangeEmail($token: ID!) { confirmChangeEmail(token: $token) } ================================================ FILE: frontend/src/graphql/mutations/DeleteDraft.gql ================================================ mutation DeleteDraft($id: ID!) { destroyDraft(id: $id) } ================================================ FILE: frontend/src/graphql/mutations/DeleteEdit.gql ================================================ mutation DeleteEdit($input: DeleteEditInput!) { deleteEdit(input: $input) } ================================================ FILE: frontend/src/graphql/mutations/DeleteFingerprintSubmissions.gql ================================================ mutation DeleteFingerprintSubmissions( $input: DeleteFingerprintSubmissionsInput! ) { sceneDeleteFingerprintSubmissions(input: $input) } ================================================ FILE: frontend/src/graphql/mutations/DeleteScene.gql ================================================ mutation DeleteScene($input: SceneDestroyInput!) { sceneDestroy(input: $input) } ================================================ FILE: frontend/src/graphql/mutations/DeleteSite.gql ================================================ mutation DeleteSite($input: SiteDestroyInput!) { siteDestroy(input: $input) } ================================================ FILE: frontend/src/graphql/mutations/DeleteStudio.gql ================================================ mutation DeleteStudio($input: StudioDestroyInput!) { studioDestroy(input: $input) } ================================================ FILE: frontend/src/graphql/mutations/DeleteTagCategory.gql ================================================ mutation DeleteTagCategory($input: TagCategoryDestroyInput!) { tagCategoryDestroy(input: $input) } ================================================ FILE: frontend/src/graphql/mutations/DeleteUser.gql ================================================ mutation DeleteUser($input: UserDestroyInput!) { userDestroy(input: $input) } ================================================ FILE: frontend/src/graphql/mutations/EditComment.gql ================================================ #import "../fragments/CommentFragment.gql" mutation EditComment($input: EditCommentInput!) { editComment(input: $input) { id comments { ...CommentFragment } } } ================================================ FILE: frontend/src/graphql/mutations/FavoritePerformer.gql ================================================ mutation FavoritePerformer($id: ID!, $favorite: Boolean!) { favoritePerformer(id: $id, favorite: $favorite) } ================================================ FILE: frontend/src/graphql/mutations/FavoriteStudio.gql ================================================ mutation FavoriteStudio($id: ID!, $favorite: Boolean!) { favoriteStudio(id: $id, favorite: $favorite) } ================================================ FILE: frontend/src/graphql/mutations/GenerateInviteCode.gql ================================================ mutation GenerateInviteCodes($input: GenerateInviteCodeInput) { generateInviteCodes(input: $input) } ================================================ FILE: frontend/src/graphql/mutations/GrantInvite.gql ================================================ mutation GrantInvite($input: GrantInviteInput!) { grantInvite(input: $input) } ================================================ FILE: frontend/src/graphql/mutations/MarkNotificationRead.gql ================================================ mutation MarkNotificationRead($notification: MarkNotificationReadInput!) { markNotificationsRead(notification: $notification) } ================================================ FILE: frontend/src/graphql/mutations/MarkNotificationsRead.gql ================================================ mutation MarkNotificationsRead { markNotificationsRead } ================================================ FILE: frontend/src/graphql/mutations/MoveFingerprintSubmissions.gql ================================================ mutation MoveFingerprintSubmissions($input: MoveFingerprintSubmissionsInput!) { sceneMoveFingerprintSubmissions(input: $input) } ================================================ FILE: frontend/src/graphql/mutations/NewUser.gql ================================================ mutation NewUser($input: NewUserInput!) { newUser(input: $input) } ================================================ FILE: frontend/src/graphql/mutations/PerformerEdit.gql ================================================ #import "../fragments/EditFragment.gql" mutation PerformerEdit($performerData: PerformerEditInput!) { performerEdit(input: $performerData) { ...EditFragment } } ================================================ FILE: frontend/src/graphql/mutations/PerformerEditUpdate.gql ================================================ #import "../fragments/EditFragment.gql" mutation PerformerEditUpdate($id: ID!, $performerData: PerformerEditInput!) { performerEditUpdate(id: $id, input: $performerData) { ...EditFragment } } ================================================ FILE: frontend/src/graphql/mutations/RegenerateAPIKey.gql ================================================ mutation RegenerateAPIKey($user_id: ID) { regenerateAPIKey(userID: $user_id) } ================================================ FILE: frontend/src/graphql/mutations/RequestChangeEmail.gql ================================================ mutation RequestChangeEmail { requestChangeEmail } ================================================ FILE: frontend/src/graphql/mutations/RescindInviteCode.gql ================================================ mutation RescindInviteCode($code: ID!) { rescindInviteCode(code: $code) } ================================================ FILE: frontend/src/graphql/mutations/ResetPassword.gql ================================================ mutation ResetPassword($input: ResetPasswordInput!) { resetPassword(input: $input) } ================================================ FILE: frontend/src/graphql/mutations/RevokeInvite.gql ================================================ mutation RevokeInvite($input: RevokeInviteInput!) { revokeInvite(input: $input) } ================================================ FILE: frontend/src/graphql/mutations/SceneEdit.gql ================================================ #import "../fragments/EditFragment.gql" mutation SceneEdit($sceneData: SceneEditInput!) { sceneEdit(input: $sceneData) { ...EditFragment } } ================================================ FILE: frontend/src/graphql/mutations/SceneEditUpdate.gql ================================================ #import "../fragments/EditFragment.gql" mutation SceneEditUpdate($id: ID!, $sceneData: SceneEditInput!) { sceneEditUpdate(id: $id, input: $sceneData) { ...EditFragment } } ================================================ FILE: frontend/src/graphql/mutations/StudioEdit.gql ================================================ #import "../fragments/EditFragment.gql" mutation StudioEdit($studioData: StudioEditInput!) { studioEdit(input: $studioData) { ...EditFragment } } ================================================ FILE: frontend/src/graphql/mutations/StudioEditUpdate.gql ================================================ #import "../fragments/EditFragment.gql" mutation StudioEditUpdate($id: ID!, $studioData: StudioEditInput!) { studioEditUpdate(id: $id, input: $studioData) { ...EditFragment } } ================================================ FILE: frontend/src/graphql/mutations/TagEdit.gql ================================================ #import "../fragments/EditFragment.gql" mutation TagEdit($tagData: TagEditInput!) { tagEdit(input: $tagData) { ...EditFragment } } ================================================ FILE: frontend/src/graphql/mutations/TagEditUpdate.gql ================================================ #import "../fragments/EditFragment.gql" mutation TagEditUpdate($id: ID!, $tagData: TagEditInput!) { tagEditUpdate(id: $id, input: $tagData) { ...EditFragment } } ================================================ FILE: frontend/src/graphql/mutations/UnmatchFingerprint.gql ================================================ mutation UnmatchFingerprint( $scene_id: ID! $algorithm: FingerprintAlgorithm! $hash: FingerprintHash! $duration: Int! ) { unmatchFingerprint: submitFingerprint( input: { vote: REMOVE scene_id: $scene_id fingerprint: { hash: $hash, algorithm: $algorithm, duration: $duration } } ) } ================================================ FILE: frontend/src/graphql/mutations/UpdateNotificationSubscriptions.gql ================================================ mutation UpdateNotificationSubscriptions($subscriptions: [NotificationEnum!]!) { updateNotificationSubscriptions(subscriptions: $subscriptions) } ================================================ FILE: frontend/src/graphql/mutations/UpdateScene.gql ================================================ mutation UpdateScene($updateData: SceneUpdateInput!) { sceneUpdate(input: $updateData) { id release_date production_date details director code duration title urls { url site { id name } } studio { id name } performers { performer { name id gender aliases } } fingerprints { hash algorithm duration } tags { id name description } } } ================================================ FILE: frontend/src/graphql/mutations/UpdateSite.gql ================================================ mutation UpdateSite($siteData: SiteUpdateInput!) { siteUpdate(input: $siteData) { id name description url regex valid_types } } ================================================ FILE: frontend/src/graphql/mutations/UpdateStudio.gql ================================================ #import "../fragments/StudioFragment.gql" mutation UpdateStudio($input: StudioUpdateInput!) { studioUpdate(input: $input) { ...StudioFragment } } ================================================ FILE: frontend/src/graphql/mutations/UpdateTagCategory.gql ================================================ mutation UpdateTagCategory($categoryData: TagCategoryUpdateInput!) { tagCategoryUpdate(input: $categoryData) { id name description group } } ================================================ FILE: frontend/src/graphql/mutations/UpdateUser.gql ================================================ mutation UpdateUser($userData: UserUpdateInput!) { userUpdate(input: $userData) { id name email roles } } ================================================ FILE: frontend/src/graphql/mutations/ValidateChangeEmail.gql ================================================ mutation ValidateChangeEmail($token: ID!, $email: String!) { validateChangeEmail(token: $token, email: $email) } ================================================ FILE: frontend/src/graphql/mutations/Vote.gql ================================================ #import "../fragments/EditFragment.gql" mutation Vote($input: EditVoteInput!) { editVote(input: $input) { ...EditFragment } } ================================================ FILE: frontend/src/graphql/mutations/index.ts ================================================ import { useMutation, type MutationHookOptions } from "@apollo/client/react"; import MeGql from "../queries/Me.gql"; import { type ActivateNewUserMutation, type ActivateNewUserMutationVariables, type AddUserMutation, type AddUserMutationVariables, type NewUserMutation, type NewUserMutationVariables, type UpdateUserMutation, type UpdateUserMutationVariables, type DeleteUserMutation, type DeleteUserMutationVariables, type AddTagCategoryMutation, type AddTagCategoryMutationVariables, type DeleteTagCategoryMutation, type DeleteTagCategoryMutationVariables, type UpdateTagCategoryMutation, type UpdateTagCategoryMutationVariables, type AddImageMutation, type AddImageMutationVariables, type PerformerEditMutation, type PerformerEditMutationVariables, type PerformerEditUpdateMutation, type PerformerEditUpdateMutationVariables, type TagEditMutation, type TagEditMutationVariables, type TagEditUpdateMutation, type TagEditUpdateMutationVariables, type AddSceneMutation, type AddSceneMutationVariables, type DeleteSceneMutation, type DeleteSceneMutationVariables, type UpdateSceneMutation, type UpdateSceneMutationVariables, type AddStudioMutation, type AddStudioMutationVariables, type DeleteStudioMutation, type DeleteStudioMutationVariables, type UpdateStudioMutation, type UpdateStudioMutationVariables, type ApplyEditMutation, type ApplyEditMutationVariables, type CancelEditMutation, type CancelEditMutationVariables, type DeleteEditMutation, type DeleteEditMutationVariables, type AmendEditMutation, type AmendEditMutationVariables, type ChangePasswordMutation, type ChangePasswordMutationVariables, type ResetPasswordMutation, type ResetPasswordMutationVariables, type RegenerateApiKeyMutation, type RegenerateApiKeyMutationVariables, type GenerateInviteCodesMutation, type GenerateInviteCodesMutationVariables, type GrantInviteMutation, type GrantInviteMutationVariables, type RescindInviteCodeMutation, type RescindInviteCodeMutationVariables, type RevokeInviteMutation, type RevokeInviteMutationVariables, type EditCommentMutation, type EditCommentMutationVariables, type StudioEditMutation, type StudioEditMutationVariables, type StudioEditUpdateMutation, type StudioEditUpdateMutationVariables, type SceneEditMutation, type SceneEditMutationVariables, type SceneEditUpdateMutation, type SceneEditUpdateMutationVariables, type VoteMutation, type VoteMutationVariables, type AddSiteMutation, type AddSiteMutationVariables, type DeleteSiteMutation, type DeleteSiteMutationVariables, type UpdateSiteMutation, type UpdateSiteMutationVariables, type FavoriteStudioMutation, type FavoriteStudioMutationVariables, type FavoritePerformerMutation, type FavoritePerformerMutationVariables, type DeleteDraftMutation, type DeleteDraftMutationVariables, type UnmatchFingerprintMutation, type UnmatchFingerprintMutationVariables, type MoveFingerprintSubmissionsMutation, type MoveFingerprintSubmissionsMutationVariables, type DeleteFingerprintSubmissionsMutation, type DeleteFingerprintSubmissionsMutationVariables, type ValidateChangeEmailMutation, type ValidateChangeEmailMutationVariables, type ConfirmChangeEmailMutation, type ConfirmChangeEmailMutationVariables, type RequestChangeEmailMutation, ActivateNewUserDocument, AddUserDocument, NewUserDocument, UpdateUserDocument, DeleteUserDocument, AddTagCategoryDocument, DeleteTagCategoryDocument, UpdateTagCategoryDocument, AddImageDocument, PerformerEditDocument, TagEditDocument, StudioEditDocument, SceneEditDocument, PerformerEditUpdateDocument, TagEditUpdateDocument, StudioEditUpdateDocument, SceneEditUpdateDocument, AddSceneDocument, DeleteSceneDocument, UpdateSceneDocument, AddStudioDocument, DeleteStudioDocument, UpdateStudioDocument, ApplyEditDocument, CancelEditDocument, DeleteEditDocument, AmendEditDocument, ChangePasswordDocument, ResetPasswordDocument, RegenerateApiKeyDocument, GenerateInviteCodesDocument, GrantInviteDocument, RescindInviteCodeDocument, RevokeInviteDocument, EditCommentDocument, VoteDocument, AddSiteDocument, DeleteSiteDocument, UpdateSiteDocument, FavoritePerformerDocument, FavoriteStudioDocument, DeleteDraftDocument, UnmatchFingerprintDocument, MoveFingerprintSubmissionsDocument, DeleteFingerprintSubmissionsDocument, ValidateChangeEmailDocument, ConfirmChangeEmailDocument, RequestChangeEmailDocument, type RequestChangeEmailMutationVariables, UpdateNotificationSubscriptionsDocument, type UpdateNotificationSubscriptionsMutation, type UpdateNotificationSubscriptionsMutationVariables, MarkNotificationsReadDocument, MarkNotificationReadDocument, type MarkNotificationReadMutationVariables, type MeQuery, } from "../types"; export const useActivateUser = ( options?: useMutation.Options< ActivateNewUserMutation, ActivateNewUserMutationVariables >, ) => useMutation(ActivateNewUserDocument, options); export const useAddUser = ( options?: useMutation.Options, ) => useMutation(AddUserDocument, options); export const useNewUser = ( options?: useMutation.Options, ) => useMutation(NewUserDocument, options); export const useUpdateUser = ( options?: useMutation.Options< UpdateUserMutation, UpdateUserMutationVariables >, ) => useMutation(UpdateUserDocument, options); export const useDeleteUser = ( options?: useMutation.Options< DeleteUserMutation, DeleteUserMutationVariables >, ) => useMutation(DeleteUserDocument, options); export const useAddCategory = ( options?: useMutation.Options< AddTagCategoryMutation, AddTagCategoryMutationVariables >, ) => useMutation(AddTagCategoryDocument, options); export const useDeleteCategory = ( options?: useMutation.Options< DeleteTagCategoryMutation, DeleteTagCategoryMutationVariables >, ) => useMutation(DeleteTagCategoryDocument, options); export const useUpdateCategory = ( options?: useMutation.Options< UpdateTagCategoryMutation, UpdateTagCategoryMutationVariables >, ) => useMutation(UpdateTagCategoryDocument, options); export const useAddImage = ( options?: useMutation.Options, ) => useMutation(AddImageDocument, options); export const usePerformerEdit = ( options?: useMutation.Options< PerformerEditMutation, PerformerEditMutationVariables >, ) => useMutation(PerformerEditDocument, options); export const usePerformerEditUpdate = ( options?: useMutation.Options< PerformerEditUpdateMutation, PerformerEditUpdateMutationVariables >, ) => useMutation(PerformerEditUpdateDocument, options); export const useAddScene = ( options?: useMutation.Options, ) => useMutation(AddSceneDocument, options); export const useDeleteScene = ( options?: useMutation.Options< DeleteSceneMutation, DeleteSceneMutationVariables >, ) => useMutation(DeleteSceneDocument, options); export const useUpdateScene = ( options?: useMutation.Options< UpdateSceneMutation, UpdateSceneMutationVariables >, ) => useMutation(UpdateSceneDocument, options); export const useAddStudio = ( options?: useMutation.Options, ) => useMutation(AddStudioDocument, options); export const useDeleteStudio = ( options?: useMutation.Options< DeleteStudioMutation, DeleteStudioMutationVariables >, ) => useMutation(DeleteStudioDocument, options); export const useUpdateStudio = ( options?: useMutation.Options< UpdateStudioMutation, UpdateStudioMutationVariables >, ) => useMutation(UpdateStudioDocument, options); export const useTagEdit = ( options?: useMutation.Options, ) => useMutation(TagEditDocument, options); export const useTagEditUpdate = ( options?: useMutation.Options< TagEditUpdateMutation, TagEditUpdateMutationVariables >, ) => useMutation(TagEditUpdateDocument, options); export const useStudioEdit = ( options?: useMutation.Options< StudioEditMutation, StudioEditMutationVariables >, ) => useMutation(StudioEditDocument, options); export const useStudioEditUpdate = ( options?: useMutation.Options< StudioEditUpdateMutation, StudioEditUpdateMutationVariables >, ) => useMutation(StudioEditUpdateDocument, options); export const useSceneEdit = ( options?: useMutation.Options, ) => useMutation(SceneEditDocument, options); export const useSceneEditUpdate = ( options?: useMutation.Options< SceneEditUpdateMutation, SceneEditUpdateMutationVariables >, ) => useMutation(SceneEditUpdateDocument, options); export const useApplyEdit = ( options?: useMutation.Options, ) => useMutation(ApplyEditDocument, options); export const useCancelEdit = ( options?: useMutation.Options< CancelEditMutation, CancelEditMutationVariables >, ) => useMutation(CancelEditDocument, options); export const useDeleteEdit = ( options?: MutationHookOptions< DeleteEditMutation, DeleteEditMutationVariables >, ) => useMutation(DeleteEditDocument, options); export const useAmendEdit = ( options?: MutationHookOptions, ) => useMutation(AmendEditDocument, options); export const useChangePassword = ( options?: useMutation.Options< ChangePasswordMutation, ChangePasswordMutationVariables >, ) => useMutation(ChangePasswordDocument, options); export const useResetPassword = ( options?: useMutation.Options< ResetPasswordMutation, ResetPasswordMutationVariables >, ) => useMutation(ResetPasswordDocument, options); export const useRegenerateAPIKey = ( options?: useMutation.Options< RegenerateApiKeyMutation, RegenerateApiKeyMutationVariables >, ) => useMutation(RegenerateApiKeyDocument, options); export const useGenerateInviteCodes = ( options?: useMutation.Options< GenerateInviteCodesMutation, GenerateInviteCodesMutationVariables >, ) => useMutation(GenerateInviteCodesDocument, options); export const useGrantInvite = ( options?: useMutation.Options< GrantInviteMutation, GrantInviteMutationVariables >, ) => useMutation(GrantInviteDocument, options); export const useRescindInviteCode = ( options?: useMutation.Options< RescindInviteCodeMutation, RescindInviteCodeMutationVariables >, ) => useMutation(RescindInviteCodeDocument, options); export const useRevokeInvite = ( options?: useMutation.Options< RevokeInviteMutation, RevokeInviteMutationVariables >, ) => useMutation(RevokeInviteDocument, options); export const useEditComment = ( options?: useMutation.Options< EditCommentMutation, EditCommentMutationVariables >, ) => useMutation(EditCommentDocument, options); export const useVote = ( options?: useMutation.Options, ) => useMutation(VoteDocument, options); export const useAddSite = ( options?: useMutation.Options, ) => useMutation(AddSiteDocument, options); export const useDeleteSite = ( options?: useMutation.Options< DeleteSiteMutation, DeleteSiteMutationVariables >, ) => useMutation(DeleteSiteDocument, options); export const useUpdateSite = ( options?: useMutation.Options< UpdateSiteMutation, UpdateSiteMutationVariables >, ) => useMutation(UpdateSiteDocument, options); export const useSetFavorite = ( type: T, id: string, ) => useMutation< T extends "performer" ? FavoritePerformerMutation : FavoriteStudioMutation, T extends "performer" ? FavoritePerformerMutationVariables : FavoriteStudioMutationVariables >(type === "performer" ? FavoritePerformerDocument : FavoriteStudioDocument, { update: (cache, { errors }) => { if (errors === undefined) { const identity = cache.identify({ __typename: type === "performer" ? "Performer" : "Studio", id, }); cache.modify({ id: identity, fields: { is_favorite: (prevState) => !prevState, }, }); } }, }); export const useDeleteDraft = ( options?: useMutation.Options< DeleteDraftMutation, DeleteDraftMutationVariables >, ) => useMutation(DeleteDraftDocument, options); export const useUnmatchFingerprint = ( options?: useMutation.Options< UnmatchFingerprintMutation, UnmatchFingerprintMutationVariables >, ) => useMutation(UnmatchFingerprintDocument, { update(cache, { data }, { variables }) { if (data?.unmatchFingerprint) cache.evict({ id: cache.identify({ __typename: "Scene", id: variables?.scene_id }), fieldName: "fingerprints", }); }, ...options, }); export const useMoveFingerprintSubmissions = ( options?: useMutation.Options< MoveFingerprintSubmissionsMutation, MoveFingerprintSubmissionsMutationVariables >, ) => useMutation(MoveFingerprintSubmissionsDocument, { update(cache, { data }, { variables }) { if (data?.sceneMoveFingerprintSubmissions) { // Evict fingerprints from both source and target scenes cache.evict({ id: cache.identify({ __typename: "Scene", id: variables?.input.source_scene_id, }), fieldName: "fingerprints", }); cache.evict({ id: cache.identify({ __typename: "Scene", id: variables?.input.target_scene_id, }), fieldName: "fingerprints", }); } }, ...options, }); export const useDeleteFingerprintSubmissions = ( options?: useMutation.Options< DeleteFingerprintSubmissionsMutation, DeleteFingerprintSubmissionsMutationVariables >, ) => useMutation(DeleteFingerprintSubmissionsDocument, { update(cache, { data }, { variables }) { if (data?.sceneDeleteFingerprintSubmissions) { cache.evict({ id: cache.identify({ __typename: "Scene", id: variables?.input.scene_id, }), fieldName: "fingerprints", }); } }, ...options, }); export const useValidateChangeEmail = ( options?: useMutation.Options< ValidateChangeEmailMutation, ValidateChangeEmailMutationVariables >, ) => useMutation(ValidateChangeEmailDocument, options); export const useConfirmChangeEmail = ( options?: useMutation.Options< ConfirmChangeEmailMutation, ConfirmChangeEmailMutationVariables >, ) => useMutation(ConfirmChangeEmailDocument, options); export const useRequestChangeEmail = ( options?: useMutation.Options< RequestChangeEmailMutation, RequestChangeEmailMutationVariables >, ) => useMutation(RequestChangeEmailDocument, options); export const useUpdateNotificationSubscriptions = ( options?: useMutation.Options< UpdateNotificationSubscriptionsMutation, UpdateNotificationSubscriptionsMutationVariables >, ) => useMutation(UpdateNotificationSubscriptionsDocument, { update(cache, { data }) { if (data?.updateNotificationSubscriptions) { const user = cache.read({ query: MeGql, optimistic: false }); cache.evict({ id: cache.identify({ __typename: "User", id: user?.me?.id }), fieldName: "notification_subscriptions", }); } }, ...options, }); export const useMarkNotificationsRead = () => useMutation(MarkNotificationsReadDocument, { update(cache, { data }) { if (data?.markNotificationsRead) { cache.evict({ fieldName: "queryNotifications" }); cache.evict({ fieldName: "getUnreadNotificationCount" }); } }, }); export const useMarkNotificationRead = ( variables: MarkNotificationReadMutationVariables, ) => useMutation(MarkNotificationReadDocument, { variables, update(cache, { data }) { if (data?.markNotificationsRead) { cache.evict({ fieldName: "queryNotifications" }); cache.evict({ fieldName: "getUnreadNotificationCount" }); } }, }); ================================================ FILE: frontend/src/graphql/queries/Categories.gql ================================================ query Categories { queryTagCategories { count tag_categories { id name description group } } } ================================================ FILE: frontend/src/graphql/queries/Category.gql ================================================ query Category($id: ID!) { findTagCategory(id: $id) { id name description group } } ================================================ FILE: frontend/src/graphql/queries/Config.gql ================================================ query Config { getConfig { edit_update_limit host_url require_invite require_activation vote_promotion_threshold vote_application_threshold voting_period min_destructive_voting_period vote_cron_interval guidelines_url require_scene_draft require_tag_role } } ================================================ FILE: frontend/src/graphql/queries/Draft.gql ================================================ #import "../fragments/ImageFragment.gql" #import "../fragments/PerformerFragment.gql" #import "../fragments/TagFragment.gql" #import "../fragments/StudioFragment.gql" query Draft($id: ID!) { findDraft(id: $id) { id created expires data { ... on PerformerDraft { id name disambiguation aliases gender birthdate deathdate urls ethnicity country eye_color hair_color height measurements breast_type tattoos piercings career_start_year career_end_year image { ...ImageFragment } } ... on SceneDraft { id title code details director date urls studio { ... on Studio { ...StudioFragment } ... on DraftEntity { draftID: id name } } performers { ... on Performer { ...PerformerFragment } ... on DraftEntity { draftID: id name } } tags { ... on Tag { ...TagFragment } ... on DraftEntity { draftID: id name } } fingerprints { hash algorithm duration } image { ...ImageFragment } } } } } ================================================ FILE: frontend/src/graphql/queries/Drafts.gql ================================================ query Drafts { findDrafts { id created expires data { ... on PerformerDraft { id name } ... on SceneDraft { id title } } } } ================================================ FILE: frontend/src/graphql/queries/Edit.gql ================================================ #import "../fragments/EditFragment.gql" query Edit($id: ID!) { findEdit(id: $id) { ...EditFragment } } ================================================ FILE: frontend/src/graphql/queries/EditUpdate.gql ================================================ #import "../fragments/PerformerFragment.gql" #import "../fragments/StudioFragment.gql" #import "../fragments/SceneFragment.gql" #import "../fragments/TagFragment.gql" #import "../fragments/FingerprintFragment.gql" query EditUpdate($id: ID!) { findEdit(id: $id) { id target_type operation status applied closed created updated updatable update_count vote_count merge_sources { ... on Tag { id } ... on Performer { id } ... on Studio { id } ... on Scene { id } } options { set_modify_aliases set_merge_aliases } user { id name } target { ... on Tag { ...TagFragment aliases } ... on Performer { ...PerformerFragment } ... on Studio { ...StudioFragment } ... on Scene { ...SceneFragment } } details { ... on TagEdit { name description category { id name } aliases } ... on PerformerEdit { name disambiguation gender birthdate deathdate ethnicity country eye_color hair_color height cup_size band_size waist_size hip_size breast_type career_start_year career_end_year aliases urls { ...URLFragment } tattoos { location description } piercings { location description } images { ...ImageFragment } draft_id } ... on StudioEdit { name urls { ...URLFragment } parent { ...StudioFragment } images { ...ImageFragment } } ... on SceneEdit { title details date production_date studio { ...StudioFragment } urls { ...URLFragment } performers { performer { ...PerformerFragment } as } tags { ...TagFragment } images { ...ImageFragment } fingerprints { ...FingerprintFragment } duration director code draft_id } } } } ================================================ FILE: frontend/src/graphql/queries/Edits.gql ================================================ #import "../fragments/EditFragment.gql" query Edits($input: EditQueryInput!) { queryEdits(input: $input) { count edits { ...EditFragment } } } ================================================ FILE: frontend/src/graphql/queries/FullPerformer.gql ================================================ #import "../fragments/PerformerFragment.gql" query FullPerformer($id: ID!) { findPerformer(id: $id) { ...PerformerFragment studios { scene_count studio { id name parent { id name } } } } } ================================================ FILE: frontend/src/graphql/queries/Me.gql ================================================ query Me { me { id name roles } } ================================================ FILE: frontend/src/graphql/queries/ModAudits.gql ================================================ query ModAudits($input: ModAuditQueryInput!) { queryModAudits(input: $input) { count audits { id action user { id name } target_id target_type data reason created_at } } } ================================================ FILE: frontend/src/graphql/queries/PendingEditsCount.gql ================================================ query PendingEditsCount($type: TargetTypeEnum!, $id: ID!) { queryEdits( input: { target_type: $type, target_id: $id, status: PENDING, per_page: 1 } ) { count } } ================================================ FILE: frontend/src/graphql/queries/Performer.gql ================================================ #import "../fragments/PerformerFragment.gql" query Performer($id: ID!) { findPerformer(id: $id) { ...PerformerFragment } } ================================================ FILE: frontend/src/graphql/queries/Performers.gql ================================================ #import "../fragments/URLFragment.gql" #import "../fragments/ImageFragment.gql" query Performers($input: PerformerQueryInput!) { queryPerformers(input: $input) { count performers { id name disambiguation deleted aliases gender birth_date age height hair_color eye_color ethnicity country career_end_year career_start_year breast_type waist_size hip_size band_size cup_size tattoos { location description } piercings { location description } urls { ...URLFragment } images { ...ImageFragment } is_favorite } } } ================================================ FILE: frontend/src/graphql/queries/PublicUser.gql ================================================ query PublicUser($name: String!) { findUser(username: $name) { id name vote_count { accept reject immediate_accept immediate_reject abstain } edit_count { immediate_accepted immediate_rejected accepted rejected failed canceled pending } } } ================================================ FILE: frontend/src/graphql/queries/QueryExistingPerformer.gql ================================================ #import "../fragments/EditFragment.gql" #import "../fragments/PerformerFragment.gql" query QueryExistingPerformer($input: QueryExistingPerformerInput!) { queryExistingPerformer(input: $input) { performers { ...PerformerFragment } edits { ...EditFragment } } } ================================================ FILE: frontend/src/graphql/queries/QueryExistingScene.gql ================================================ #import "../fragments/EditFragment.gql" #import "../fragments/SceneFragment.gql" query QueryExistingScene($input: QueryExistingSceneInput!) { queryExistingScene(input: $input) { scenes { ...SceneFragment } edits { ...EditFragment } } } ================================================ FILE: frontend/src/graphql/queries/QueryNotifications.gql ================================================ #import "../fragments/SceneFragment.gql" #import "../fragments/EditFragment.gql" #import "../fragments/CommentFragment.gql" fragment NotificationCommentFragment on EditComment { ...CommentFragment edit { ...EditFragment } } query Notifications($input: QueryNotificationsInput!) { queryNotifications(input: $input) { count notifications { created read data { __typename ... on FavoritePerformerScene { scene { ...SceneFragment } } ... on FavoritePerformerEdit { edit { ...EditFragment } } ... on FavoriteStudioScene { scene { ...SceneFragment } } ... on FavoriteStudioEdit { edit { ...EditFragment } } ... on CommentOwnEdit { comment { ...NotificationCommentFragment } } ... on CommentCommentedEdit { comment { ...NotificationCommentFragment } } ... on CommentVotedEdit { comment { ...NotificationCommentFragment } } ... on DownvoteOwnEdit { edit { ...EditFragment } } ... on FailedOwnEdit { edit { ...EditFragment } } ... on UpdatedEdit { edit { ...EditFragment } } ... on FingerprintedSceneEdit { edit { ...EditFragment } } } } } } ================================================ FILE: frontend/src/graphql/queries/Scene.gql ================================================ #import "../fragments/SceneFragment.gql" query Scene($id: ID!) { findScene(id: $id) { ...SceneFragment } } ================================================ FILE: frontend/src/graphql/queries/ScenePairings.gql ================================================ #import "../fragments/ImageFragment.gql" query ScenePairings( $performerId: ID! $names: String $gender: GenderFilterEnum $favorite: Boolean $page: Int! = 1 $per_page: Int! = 25 $direction: SortDirectionEnum! $sort: PerformerSortEnum! $fetchScenes: Boolean! ) { queryPerformers( input: { performed_with: $performerId names: $names gender: $gender is_favorite: $favorite page: $page per_page: $per_page direction: $direction sort: $sort } ) { count performers { id name disambiguation deleted aliases gender birth_date is_favorite images { ...ImageFragment } scenes(input: { performed_with: $performerId }) @include(if: $fetchScenes) { id title date duration release_date studio { id name } images { ...ImageFragment } } } } } ================================================ FILE: frontend/src/graphql/queries/Scenes.gql ================================================ #import "../fragments/QuerySceneFragment.gql" query Scenes($input: SceneQueryInput!) { queryScenes(input: $input) { count scenes { ...QuerySceneFragment } } } ================================================ FILE: frontend/src/graphql/queries/ScenesWithFingerprints.gql ================================================ #import "../fragments/QuerySceneFragment.gql" query ScenesWithFingerprints($input: SceneQueryInput!, $submitted: Boolean!) { queryScenes(input: $input) { count scenes { ...QuerySceneFragment fingerprints(is_submitted: $submitted) { hash algorithm duration submissions user_submitted created updated } } } } ================================================ FILE: frontend/src/graphql/queries/ScenesWithoutCount.gql ================================================ #import "../fragments/QuerySceneFragment.gql" query ScenesWithoutCount($input: SceneQueryInput!) { queryScenes(input: $input) { scenes { ...QuerySceneFragment } } } ================================================ FILE: frontend/src/graphql/queries/SearchAll.gql ================================================ #import "../fragments/ImageFragment.gql" #import "../fragments/SearchPerformerFragment.gql" #import "../fragments/URLFragment.gql" query SearchAll($term: String!, $limit: Int = 5) { searchPerformers(term: $term, limit: $limit) { count performers { ...SearchPerformerFragment } } searchScenes(term: $term, limit: $limit) { count scenes { id release_date title deleted duration code urls { ...URLFragment } images { ...ImageFragment } studio { id name } performers { as performer { id name disambiguation gender aliases deleted } } } } } ================================================ FILE: frontend/src/graphql/queries/SearchPerformers.gql ================================================ #import "../fragments/SearchPerformerFragment.gql" query SearchPerformers( $term: String! $page: Int $per_page: Int $filter: PerformerSearchFilter $studioId: ID $hasStudioId: Boolean! = false ) { searchPerformers( term: $term page: $page per_page: $per_page filter: $filter ) { count performers { ...SearchPerformerFragment studios(studio_id: $studioId) @include(if: $hasStudioId) { scene_count } } facets { genders { gender count } } } } ================================================ FILE: frontend/src/graphql/queries/SearchScenes.gql ================================================ #import "../fragments/ImageFragment.gql" #import "../fragments/URLFragment.gql" query SearchScenes($term: String!, $page: Int, $per_page: Int) { searchScenes(term: $term, page: $page, per_page: $per_page) { count scenes { id release_date title deleted duration code urls { ...URLFragment } images { ...ImageFragment } studio { id name } performers { as performer { id name disambiguation gender aliases deleted } } } } } ================================================ FILE: frontend/src/graphql/queries/SearchTags.gql ================================================ fragment SearchTagFragment on Tag { deleted id name description aliases } query SearchTags($term: String!, $limit: Int = 5) { exact: findTagOrAlias(name: $term) { ...SearchTagFragment } query: searchTag(term: $term, limit: $limit) { ...SearchTagFragment } } ================================================ FILE: frontend/src/graphql/queries/Site.gql ================================================ query Site($id: ID!) { findSite(id: $id) { id name description url regex valid_types icon created updated } } ================================================ FILE: frontend/src/graphql/queries/Sites.gql ================================================ query Sites { querySites { sites { id name description url regex valid_types icon created updated } } } ================================================ FILE: frontend/src/graphql/queries/Studio.gql ================================================ #import "../fragments/StudioFragment.gql" query Studio($id: ID!) { findStudio(id: $id) { ...StudioFragment sub_studios { count } } } ================================================ FILE: frontend/src/graphql/queries/StudioPerformers.gql ================================================ #import "../fragments/ImageFragment.gql" query StudioPerformers( $studioId: ID! $gender: GenderFilterEnum $favorite: Boolean $names: String $page: Int! = 1 $per_page: Int! = 25 $direction: SortDirectionEnum! $sort: PerformerSortEnum! ) { queryPerformers( input: { studio_id: $studioId gender: $gender is_favorite: $favorite names: $names page: $page per_page: $per_page direction: $direction sort: $sort } ) { count performers { id name disambiguation deleted aliases gender birth_date is_favorite images { ...ImageFragment } scenes(input: { studio_id: $studioId }) { id title duration release_date production_date studio { id name } images { ...ImageFragment } } } } } ================================================ FILE: frontend/src/graphql/queries/Studios.gql ================================================ #import "../fragments/URLFragment.gql" #import "../fragments/ImageFragment.gql" query Studios($input: StudioQueryInput!) { queryStudios(input: $input) { count studios { id name aliases deleted parent { id name } urls { ...URLFragment } images { ...ImageFragment } is_favorite } } } ================================================ FILE: frontend/src/graphql/queries/SubStudios.gql ================================================ query SubStudios($id: ID!, $input: StudioQueryInput!) { findStudio(id: $id) { sub_studios(input: $input) { count studios { id name } } } } ================================================ FILE: frontend/src/graphql/queries/Tag.gql ================================================ query Tag($name: String, $id: ID) { findTag(name: $name, id: $id) { id name description aliases deleted category { id name group description } } } ================================================ FILE: frontend/src/graphql/queries/Tags.gql ================================================ query Tags($input: TagQueryInput!) { queryTags(input: $input) { count tags { id name description aliases } } } ================================================ FILE: frontend/src/graphql/queries/UnreadNotificationCount.gql ================================================ query UnreadNotificationCount { getUnreadNotificationCount } ================================================ FILE: frontend/src/graphql/queries/User.gql ================================================ query User($name: String!) { findUser(username: $name) { id name email roles api_key api_calls invited_by { id name } invite_tokens invite_codes { id uses expires } vote_count { accept reject immediate_accept immediate_reject abstain } edit_count { immediate_accepted immediate_rejected accepted rejected failed canceled pending } notification_subscriptions } } ================================================ FILE: frontend/src/graphql/queries/Users.gql ================================================ query Users($input: UserQueryInput!) { queryUsers(input: $input) { count users { id name email roles api_key api_calls invited_by { id name } invite_tokens } } } ================================================ FILE: frontend/src/graphql/queries/Version.gql ================================================ query Version { version { hash version build_time build_type } } ================================================ FILE: frontend/src/graphql/queries/index.ts ================================================ import { useLazyQuery, useQuery } from "@apollo/client/react"; import { CategoryDocument, type CategoryQueryVariables, CategoriesDocument, EditDocument, type EditQueryVariables, EditUpdateDocument, EditsDocument, type EditsQueryVariables, MeDocument, type MeQuery, PerformerDocument, type PerformerQueryVariables, FullPerformerDocument, PerformersDocument, type PerformersQueryVariables, SceneDocument, type SceneQueryVariables, ScenesDocument, type ScenesQueryVariables, ScenesWithFingerprintsDocument, type ScenesWithFingerprintsQueryVariables, ScenesWithoutCountDocument, SearchAllDocument, type SearchAllQuery, type SearchAllQueryVariables, SearchPerformersDocument, type SearchPerformersQuery, type SearchPerformersQueryVariables, SearchScenesDocument, type SearchScenesQuery, type SearchScenesQueryVariables, SearchTagsDocument, type SearchTagsQueryVariables, StudioDocument, type StudioQueryVariables, StudiosDocument, type StudiosQuery, type StudiosQueryVariables, TagDocument, type TagQueryVariables, TagsDocument, type TagsQuery, type TagsQueryVariables, UserDocument, type UserQueryVariables, UsersDocument, type UsersQueryVariables, PublicUserDocument, type PublicUserQueryVariables, ConfigDocument, PendingEditsCountDocument, type PendingEditsCountQueryVariables, SiteDocument, type SiteQueryVariables, SitesDocument, DraftDocument, type DraftQueryVariables, DraftsDocument, QueryExistingSceneDocument, type QueryExistingSceneQueryVariables, QueryExistingPerformerDocument, type QueryExistingPerformerQueryVariables, ScenePairingsDocument, type ScenePairingsQueryVariables, StudioPerformersDocument, type StudioPerformersQueryVariables, SubStudiosDocument, type SubStudiosQueryVariables, VersionDocument, type MeQueryVariables, NotificationsDocument, type NotificationsQueryVariables, UnreadNotificationCountDocument, ModAuditsDocument, type ModAuditsQueryVariables, } from "../types"; import { useCurrentUser } from "src/hooks"; export const useCategory = (variables: CategoryQueryVariables, skip = false) => useQuery(CategoryDocument, { variables, skip, }); export const useCategories = () => useQuery(CategoriesDocument); export const useEdit = (variables: EditQueryVariables, skip = false) => useQuery(EditDocument, { variables, skip, }); export const useEditUpdate = (variables: EditQueryVariables, skip = false) => useQuery(EditUpdateDocument, { variables, skip, }); export const useEdits = (variables: EditsQueryVariables) => useQuery(EditsDocument, { variables, }); export const useMe = (options?: useQuery.Options) => useQuery(MeDocument, options); export const usePerformer = ( variables: PerformerQueryVariables, skip = false, ) => useQuery(PerformerDocument, { variables, skip, }); export const useFullPerformer = ( variables: PerformerQueryVariables, skip = false, ) => useQuery(FullPerformerDocument, { variables, skip, }); export const usePerformers = (variables: PerformersQueryVariables) => useQuery(PerformersDocument, { variables, }); export const useScene = (variables: SceneQueryVariables, skip = false) => useQuery(SceneDocument, { variables, skip, }); export const useScenes = (variables: ScenesQueryVariables, skip = false) => useQuery(ScenesDocument, { variables, skip, }); export const useScenesWithFingerprints = ( variables: ScenesWithFingerprintsQueryVariables, skip = false, ) => useQuery(ScenesWithFingerprintsDocument, { variables, skip, }); export const useScenesWithoutCount = ( variables: ScenesQueryVariables, skip = false, ) => useQuery(ScenesWithoutCountDocument, { variables, skip, }); export const useSearchAll = ( variables: SearchAllQueryVariables, skip = false, ) => useQuery(SearchAllDocument, { variables, skip, }); export const useSearchPerformers = ( variables: SearchPerformersQueryVariables, skip = false, ) => useQuery(SearchPerformersDocument, { variables, skip, }); export const useSearchScenes = ( variables: SearchScenesQueryVariables, skip = false, ) => useQuery(SearchScenesDocument, { variables, skip, }); export const useLazySearchAll = ( options?: useLazyQuery.Options, ) => useLazyQuery(SearchAllDocument, options); export const useLazySearchPerformers = ( options?: useLazyQuery.Options< SearchPerformersQuery, SearchPerformersQueryVariables >, ) => useLazyQuery(SearchPerformersDocument, options); export const useLazySearchScenes = ( options?: useLazyQuery.Options, ) => useLazyQuery(SearchScenesDocument, options); export const useSearchTags = (variables: SearchTagsQueryVariables) => useQuery(SearchTagsDocument, { variables, }); export const useStudio = (variables: StudioQueryVariables, skip = false) => useQuery(StudioDocument, { variables, skip, }); export const useStudios = (variables: StudiosQueryVariables) => useQuery(StudiosDocument, { variables, }); export const useSubStudios = (variables: SubStudiosQueryVariables) => useQuery(SubStudiosDocument, { variables, }); export const useLazyStudios = ( options?: useLazyQuery.Options, ) => useLazyQuery(StudiosDocument, options); export const useTag = (variables: TagQueryVariables, skip = false) => useQuery(TagDocument, { variables, skip, }); export const useTags = (variables: TagsQueryVariables) => useQuery(TagsDocument, { variables, }); export const useLazyTags = ( options?: useLazyQuery.Options, ) => useLazyQuery(TagsDocument, options); export const usePrivateUser = (variables: UserQueryVariables, skip = false) => useQuery(UserDocument, { variables, skip, }); export const usePublicUser = ( variables: PublicUserQueryVariables, skip = false, ) => useQuery(PublicUserDocument, { variables, skip, }); export const useUser = (variables: UserQueryVariables, skip = false) => { const { isAdmin, user } = useCurrentUser(); const isUser = () => user?.name === variables.name; const showPrivate = isUser() || isAdmin; const privateUser = usePrivateUser(variables, skip || !showPrivate); const publicUser = usePublicUser(variables, skip || showPrivate); return showPrivate ? privateUser : publicUser; }; export const useUsers = (variables: UsersQueryVariables) => useQuery(UsersDocument, { variables, }); export const useConfig = () => useQuery(ConfigDocument); export const useVersion = () => useQuery(VersionDocument); export const usePendingEditsCount = ( variables: PendingEditsCountQueryVariables, ) => useQuery(PendingEditsCountDocument, { variables }); export const useSite = (variables: SiteQueryVariables, skip = false) => useQuery(SiteDocument, { variables, skip, }); export const useSites = () => useQuery(SitesDocument); export const useDraft = (variables: DraftQueryVariables, skip = false) => useQuery(DraftDocument, { variables, skip, }); export const useDrafts = () => useQuery(DraftsDocument); export const useQueryExistingScene = ( variables: QueryExistingSceneQueryVariables, skip = false, ) => useQuery(QueryExistingSceneDocument, { variables, skip, }); export const useQueryExistingPerformer = ( variables: QueryExistingPerformerQueryVariables, skip = false, ) => useQuery(QueryExistingPerformerDocument, { variables, skip, }); export const useScenePairings = (variables: ScenePairingsQueryVariables) => useQuery(ScenePairingsDocument, { variables, }); export const useStudioPerformers = ( variables: StudioPerformersQueryVariables, ) => useQuery(StudioPerformersDocument, { variables, }); export const useNotifications = (variables: NotificationsQueryVariables) => useQuery(NotificationsDocument, { variables, }); export const useUnreadNotificationsCount = () => useQuery(UnreadNotificationCountDocument); export const useModAudits = (variables: ModAuditsQueryVariables) => useQuery(ModAuditsDocument, { variables, }); ================================================ FILE: frontend/src/graphql/scalars.d.ts ================================================ type GQLDate = string; type GQLTime = string; type GQLUpload = File; ================================================ FILE: frontend/src/graphql/types.ts ================================================ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; export type MakeEmpty = { [_ in K]?: never }; export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: { input: string; output: string; } String: { input: string; output: string; } Boolean: { input: boolean; output: boolean; } Int: { input: number; output: number; } Float: { input: number; output: number; } Date: { input: string; output: string; } DateTime: { input: string; output: string; } FingerprintHash: { input: string; output: string; } Time: { input: string; output: string; } Upload: { input: File; output: File; } }; export type ActivateNewUserInput = { activation_key: Scalars['ID']['input']; name: Scalars['String']['input']; password: Scalars['String']['input']; }; export type AmendEditInput = { id: Scalars['ID']['input']; reason: Scalars['String']['input']; /** Array items to remove from added arrays */ remove_added_items?: InputMaybe>; /** Fields to remove from the diff (e.g., ["name", "disambiguation"]) */ remove_fields?: InputMaybe>; /** Array items to remove from removed arrays */ remove_removed_items?: InputMaybe>; }; export type AmendItemRemoval = { /** Field name (e.g., "aliases", "urls", "images") */ field: Scalars['String']['input']; /** Indices to remove from the array */ indices: Array; }; export type ApplyEditInput = { id: Scalars['ID']['input']; }; export type BodyModification = { __typename: 'BodyModification'; description?: Maybe; location: Scalars['String']['output']; }; export type BodyModificationCriterionInput = { description?: InputMaybe; location?: InputMaybe; modifier: CriterionModifier; }; export type BodyModificationInput = { description?: InputMaybe; location: Scalars['String']['input']; }; export type BreastTypeCriterionInput = { modifier: CriterionModifier; value?: InputMaybe; }; export enum BreastTypeEnum { FAKE = 'FAKE', NA = 'NA', NATURAL = 'NATURAL' } export type CancelEditInput = { id: Scalars['ID']['input']; }; export type CommentCommentedEdit = { __typename: 'CommentCommentedEdit'; comment: EditComment; }; export type CommentOwnEdit = { __typename: 'CommentOwnEdit'; comment: EditComment; }; export type CommentVotedEdit = { __typename: 'CommentVotedEdit'; comment: EditComment; }; export enum CriterionModifier { /** = */ EQUALS = 'EQUALS', EXCLUDES = 'EXCLUDES', /** > */ GREATER_THAN = 'GREATER_THAN', INCLUDES = 'INCLUDES', /** INCLUDES ALL */ INCLUDES_ALL = 'INCLUDES_ALL', /** IS NULL */ IS_NULL = 'IS_NULL', /** < */ LESS_THAN = 'LESS_THAN', /** != */ NOT_EQUALS = 'NOT_EQUALS', /** IS NOT NULL */ NOT_NULL = 'NOT_NULL' } export enum DateAccuracyEnum { DAY = 'DAY', MONTH = 'MONTH', YEAR = 'YEAR' } export type DateCriterionInput = { modifier: CriterionModifier; value: Scalars['Date']['input']; }; export type DeleteEditInput = { id: Scalars['ID']['input']; reason: Scalars['String']['input']; }; export type DeleteFingerprintSubmissionsInput = { fingerprints: Array; scene_id: Scalars['ID']['input']; }; export type DownvoteOwnEdit = { __typename: 'DownvoteOwnEdit'; edit: Edit; }; export type Draft = { __typename: 'Draft'; created: Scalars['Time']['output']; data: DraftData; expires: Scalars['Time']['output']; id: Scalars['ID']['output']; }; export type DraftData = PerformerDraft | SceneDraft; export type DraftEntity = { __typename: 'DraftEntity'; id?: Maybe; name: Scalars['String']['output']; }; export type DraftEntityInput = { id?: InputMaybe; name: Scalars['String']['input']; }; export type DraftFingerprint = { __typename: 'DraftFingerprint'; algorithm: FingerprintAlgorithm; duration: Scalars['Int']['output']; hash: Scalars['FingerprintHash']['output']; }; export type DraftSubmissionStatus = { __typename: 'DraftSubmissionStatus'; id?: Maybe; }; export type Edit = { __typename: 'Edit'; applied: Scalars['Boolean']['output']; bot: Scalars['Boolean']['output']; closed?: Maybe; comments: Array; created: Scalars['Time']['output']; /** Is the edit considered destructive. */ destructive: Scalars['Boolean']['output']; details?: Maybe; expires?: Maybe; id: Scalars['ID']['output']; /** Objects to merge with the target. Only applicable to merges */ merge_sources: Array; /** Previous state of fields being modified - null if operation is create or delete. */ old_details?: Maybe; operation: OperationEnum; /** Entity specific options */ options?: Maybe; status: VoteStatusEnum; /** Object being edited - null if creating a new object */ target?: Maybe; target_type: TargetTypeEnum; updatable: Scalars['Boolean']['output']; update_count: Scalars['Int']['output']; updated?: Maybe; user?: Maybe; /** = Accepted - Rejected */ vote_count: Scalars['Int']['output']; votes: Array; }; export type EditComment = { __typename: 'EditComment'; comment: Scalars['String']['output']; date: Scalars['Time']['output']; edit: Edit; id: Scalars['ID']['output']; user?: Maybe; }; export type EditCommentInput = { comment: Scalars['String']['input']; id: Scalars['ID']['input']; }; export type EditDetails = PerformerEdit | SceneEdit | StudioEdit | TagEdit; export type EditInput = { /** Edit submitted by an automated script. Requires bot permission */ bot?: InputMaybe; comment?: InputMaybe; /** Not required for create type */ id?: InputMaybe; /** Only required for merge type */ merge_source_ids?: InputMaybe>; operation: OperationEnum; }; export type EditQueryInput = { /** Filter by applied status */ applied?: InputMaybe; direction?: SortDirectionEnum; /** Filter out user's own edits */ include_user_submitted?: InputMaybe; /** Filter to bot edits only */ is_bot?: InputMaybe; /** Filter by favorite status */ is_favorite?: InputMaybe; /** Filter by operation */ operation?: InputMaybe; page?: Scalars['Int']['input']; per_page?: Scalars['Int']['input']; sort?: EditSortEnum; /** Filter by status */ status?: InputMaybe; /** Filter by target id */ target_id?: InputMaybe; /** Filter by target type */ target_type?: InputMaybe; /** Filter by user id */ user_id?: InputMaybe; /** Filter by vote count */ vote_count?: InputMaybe; /** Filter by user voted status */ voted?: InputMaybe; }; export enum EditSortEnum { CLOSED_AT = 'CLOSED_AT', CREATED_AT = 'CREATED_AT', UPDATED_AT = 'UPDATED_AT' } export type EditTarget = Performer | Scene | Studio | Tag; export type EditVote = { __typename: 'EditVote'; date: Scalars['Time']['output']; user?: Maybe; vote: VoteTypeEnum; }; export type EditVoteInput = { id: Scalars['ID']['input']; vote: VoteTypeEnum; }; export enum EthnicityEnum { ASIAN = 'ASIAN', BLACK = 'BLACK', CAUCASIAN = 'CAUCASIAN', INDIAN = 'INDIAN', LATIN = 'LATIN', MIDDLE_EASTERN = 'MIDDLE_EASTERN', MIXED = 'MIXED', OTHER = 'OTHER' } export enum EthnicityFilterEnum { ASIAN = 'ASIAN', BLACK = 'BLACK', CAUCASIAN = 'CAUCASIAN', INDIAN = 'INDIAN', LATIN = 'LATIN', MIDDLE_EASTERN = 'MIDDLE_EASTERN', MIXED = 'MIXED', OTHER = 'OTHER', UNKNOWN = 'UNKNOWN' } export type EyeColorCriterionInput = { modifier: CriterionModifier; value?: InputMaybe; }; export enum EyeColorEnum { BLUE = 'BLUE', BROWN = 'BROWN', GREEN = 'GREEN', GREY = 'GREY', HAZEL = 'HAZEL', RED = 'RED' } export type FailedOwnEdit = { __typename: 'FailedOwnEdit'; edit: Edit; }; export enum FavoriteFilter { ALL = 'ALL', PERFORMER = 'PERFORMER', STUDIO = 'STUDIO' } export type FavoritePerformerEdit = { __typename: 'FavoritePerformerEdit'; edit: Edit; }; export type FavoritePerformerScene = { __typename: 'FavoritePerformerScene'; scene: Scene; }; export type FavoriteStudioEdit = { __typename: 'FavoriteStudioEdit'; edit: Edit; }; export type FavoriteStudioScene = { __typename: 'FavoriteStudioScene'; scene: Scene; }; export type Fingerprint = { __typename: 'Fingerprint'; algorithm: FingerprintAlgorithm; created: Scalars['Time']['output']; duration: Scalars['Int']['output']; hash: Scalars['FingerprintHash']['output']; /** number of times this fingerprint has been reported */ reports: Scalars['Int']['output']; /** number of times this fingerprint has been submitted (excluding reports) */ submissions: Scalars['Int']['output']; updated: Scalars['Time']['output']; /** true if the current user reported this fingerprint */ user_reported: Scalars['Boolean']['output']; /** true if the current user submitted this fingerprint */ user_submitted: Scalars['Boolean']['output']; }; export enum FingerprintAlgorithm { MD5 = 'MD5', OSHASH = 'OSHASH', PHASH = 'PHASH' } export type FingerprintBatchSubmission = { algorithm: FingerprintAlgorithm; duration: Scalars['Int']['input']; hash: Scalars['FingerprintHash']['input']; scene_id: Scalars['ID']['input']; }; export type FingerprintEditInput = { algorithm: FingerprintAlgorithm; created: Scalars['Time']['input']; duration: Scalars['Int']['input']; hash: Scalars['FingerprintHash']['input']; /** @deprecated Unused */ submissions?: InputMaybe; /** @deprecated Unused */ updated?: InputMaybe; user_ids?: InputMaybe>; }; export type FingerprintInput = { algorithm: FingerprintAlgorithm; duration: Scalars['Int']['input']; hash: Scalars['FingerprintHash']['input']; /** assumes current user if omitted. Ignored for non-modify Users */ user_ids?: InputMaybe>; }; export type FingerprintQueryInput = { algorithm: FingerprintAlgorithm; hash: Scalars['FingerprintHash']['input']; }; export type FingerprintSubmission = { fingerprint: FingerprintInput; scene_id: Scalars['ID']['input']; /** @deprecated Use `vote` with REMOVE instead */ unmatch?: InputMaybe; vote?: InputMaybe; }; export type FingerprintSubmissionResult = { __typename: 'FingerprintSubmissionResult'; /** Error message if submission failed */ error?: Maybe; /** The fingerprint hash that was submitted */ hash: Scalars['FingerprintHash']['output']; /** The scene ID that was submitted to */ scene_id: Scalars['ID']['output']; }; export enum FingerprintSubmissionType { /** Report as invalid */ INVALID = 'INVALID', /** Remove vote */ REMOVE = 'REMOVE', /** Positive vote */ VALID = 'VALID' } export type FingerprintedSceneEdit = { __typename: 'FingerprintedSceneEdit'; edit: Edit; }; export type FuzzyDate = { __typename: 'FuzzyDate'; accuracy: DateAccuracyEnum; date: Scalars['Date']['output']; }; export enum GenderEnum { FEMALE = 'FEMALE', INTERSEX = 'INTERSEX', MALE = 'MALE', NON_BINARY = 'NON_BINARY', TRANSGENDER_FEMALE = 'TRANSGENDER_FEMALE', TRANSGENDER_MALE = 'TRANSGENDER_MALE' } export type GenderFacet = { __typename: 'GenderFacet'; count: Scalars['Int']['output']; gender: GenderEnum; }; export enum GenderFilterEnum { FEMALE = 'FEMALE', INTERSEX = 'INTERSEX', MALE = 'MALE', NON_BINARY = 'NON_BINARY', TRANSGENDER_FEMALE = 'TRANSGENDER_FEMALE', TRANSGENDER_MALE = 'TRANSGENDER_MALE', UNKNOWN = 'UNKNOWN' } export type GenerateInviteCodeInput = { keys?: InputMaybe; ttl?: InputMaybe; uses?: InputMaybe; }; export type GrantInviteInput = { amount: Scalars['Int']['input']; user_id: Scalars['ID']['input']; }; export type HairColorCriterionInput = { modifier: CriterionModifier; value?: InputMaybe; }; export enum HairColorEnum { AUBURN = 'AUBURN', BALD = 'BALD', BLACK = 'BLACK', BLONDE = 'BLONDE', BRUNETTE = 'BRUNETTE', GREY = 'GREY', OTHER = 'OTHER', RED = 'RED', VARIOUS = 'VARIOUS', WHITE = 'WHITE' } export type IdCriterionInput = { modifier: CriterionModifier; value: Array; }; export type Image = { __typename: 'Image'; height: Scalars['Int']['output']; id: Scalars['ID']['output']; url: Scalars['String']['output']; width: Scalars['Int']['output']; }; export type ImageCreateInput = { file?: InputMaybe; url?: InputMaybe; }; export type ImageDestroyInput = { id: Scalars['ID']['input']; }; export type ImageUpdateInput = { id: Scalars['ID']['input']; url?: InputMaybe; }; export type IntCriterionInput = { modifier: CriterionModifier; value: Scalars['Int']['input']; }; export type InviteKey = { __typename: 'InviteKey'; expires?: Maybe; id: Scalars['ID']['output']; uses?: Maybe; }; export type MarkNotificationReadInput = { id: Scalars['ID']['input']; type: NotificationEnum; }; export type Measurements = { __typename: 'Measurements'; band_size?: Maybe; cup_size?: Maybe; hip?: Maybe; waist?: Maybe; }; export type ModAudit = { __typename: 'ModAudit'; action: ModAuditActionEnum; created_at: Scalars['Time']['output']; data: Scalars['String']['output']; id: Scalars['ID']['output']; reason?: Maybe; target_id: Scalars['ID']['output']; target_type: Scalars['String']['output']; user?: Maybe; }; export enum ModAuditActionEnum { EDIT_AMENDMENT = 'EDIT_AMENDMENT', EDIT_DELETE = 'EDIT_DELETE' } export type ModAuditQueryInput = { action?: InputMaybe; page?: Scalars['Int']['input']; per_page?: Scalars['Int']['input']; user_id?: InputMaybe; }; export type MoveFingerprintSubmissionsInput = { fingerprints: Array; source_scene_id: Scalars['ID']['input']; target_scene_id: Scalars['ID']['input']; }; export type MultiIdCriterionInput = { modifier: CriterionModifier; value?: InputMaybe>; }; export type MultiStringCriterionInput = { modifier: CriterionModifier; value: Array; }; export type Mutation = { __typename: 'Mutation'; activateNewUser?: Maybe; /** Amend a closed edit by removing fields - moderator only */ amendEdit: Edit; /** Apply edit without voting */ applyEdit: Edit; /** Cancel edit without voting */ cancelEdit: Edit; /** Changes the password for the current user */ changePassword: Scalars['Boolean']['output']; confirmChangeEmail: UserChangeEmailStatus; /** Delete a closed edit - moderator only */ deleteEdit: Scalars['Boolean']['output']; destroyDraft: Scalars['Boolean']['output']; /** Comment on an edit */ editComment: Edit; /** Vote to accept/reject an edit */ editVote: Edit; /** Favorite or unfavorite a performer */ favoritePerformer: Scalars['Boolean']['output']; /** Favorite or unfavorite a studio */ favoriteStudio: Scalars['Boolean']['output']; /** @deprecated Use generateInviteCodes */ generateInviteCode?: Maybe; /** Generates an invite code using an invite token */ generateInviteCodes: Array; /** Adds invite tokens for a user */ grantInvite: Scalars['Int']['output']; imageCreate?: Maybe; imageDestroy: Scalars['Boolean']['output']; /** Mark all of the current users notifications as read. */ markNotificationsRead: Scalars['Boolean']['output']; /** User interface for registering */ newUser?: Maybe; performerCreate?: Maybe; performerDestroy: Scalars['Boolean']['output']; /** Propose a new performer or modification to a performer */ performerEdit: Edit; /** Update a pending performer edit */ performerEditUpdate: Edit; performerUpdate?: Maybe; /** Regenerates the api key for the given user, or the current user if id not provided */ regenerateAPIKey: Scalars['String']['output']; /** Request an email change for the current user */ requestChangeEmail: UserChangeEmailStatus; /** Removes a pending invite code - refunding the token */ rescindInviteCode: Scalars['Boolean']['output']; /** Generates an email to reset a user password */ resetPassword: Scalars['Boolean']['output']; /** Removes invite tokens from a user */ revokeInvite: Scalars['Int']['output']; sceneCreate?: Maybe; /** Delete all fingerprint submissions for a specific fingerprint on a scene */ sceneDeleteFingerprintSubmissions: Scalars['Boolean']['output']; sceneDestroy: Scalars['Boolean']['output']; /** Propose a new scene or modification to a scene */ sceneEdit: Edit; /** Update a pending scene edit */ sceneEditUpdate: Edit; /** Move all fingerprint submissions from source scene to target scene */ sceneMoveFingerprintSubmissions: Scalars['Boolean']['output']; sceneUpdate?: Maybe; siteCreate?: Maybe; siteDestroy: Scalars['Boolean']['output']; siteUpdate?: Maybe; studioCreate?: Maybe; studioDestroy: Scalars['Boolean']['output']; /** Propose a new studio or modification to a studio */ studioEdit: Edit; /** Update a pending studio edit */ studioEditUpdate: Edit; studioUpdate?: Maybe; /** Matches/unmatches a scene to fingerprint */ submitFingerprint: Scalars['Boolean']['output']; /** Batch submit up to 1000 fingerprint matches */ submitFingerprints: Array; submitPerformerDraft: DraftSubmissionStatus; /** Draft submissions */ submitSceneDraft: DraftSubmissionStatus; tagCategoryCreate?: Maybe; tagCategoryDestroy: Scalars['Boolean']['output']; tagCategoryUpdate?: Maybe; tagCreate?: Maybe; tagDestroy: Scalars['Boolean']['output']; /** Propose a new tag or modification to a tag */ tagEdit: Edit; /** Update a pending tag edit */ tagEditUpdate: Edit; tagUpdate?: Maybe; /** Update notification subscriptions for current user. */ updateNotificationSubscriptions: Scalars['Boolean']['output']; userCreate?: Maybe; userDestroy: Scalars['Boolean']['output']; userUpdate?: Maybe; validateChangeEmail: UserChangeEmailStatus; }; export type MutationActivateNewUserArgs = { input: ActivateNewUserInput; }; export type MutationAmendEditArgs = { input: AmendEditInput; }; export type MutationApplyEditArgs = { input: ApplyEditInput; }; export type MutationCancelEditArgs = { input: CancelEditInput; }; export type MutationChangePasswordArgs = { input: UserChangePasswordInput; }; export type MutationConfirmChangeEmailArgs = { token: Scalars['ID']['input']; }; export type MutationDeleteEditArgs = { input: DeleteEditInput; }; export type MutationDestroyDraftArgs = { id: Scalars['ID']['input']; }; export type MutationEditCommentArgs = { input: EditCommentInput; }; export type MutationEditVoteArgs = { input: EditVoteInput; }; export type MutationFavoritePerformerArgs = { favorite: Scalars['Boolean']['input']; id: Scalars['ID']['input']; }; export type MutationFavoriteStudioArgs = { favorite: Scalars['Boolean']['input']; id: Scalars['ID']['input']; }; export type MutationGenerateInviteCodesArgs = { input?: InputMaybe; }; export type MutationGrantInviteArgs = { input: GrantInviteInput; }; export type MutationImageCreateArgs = { input: ImageCreateInput; }; export type MutationImageDestroyArgs = { input: ImageDestroyInput; }; export type MutationMarkNotificationsReadArgs = { notification?: InputMaybe; }; export type MutationNewUserArgs = { input: NewUserInput; }; export type MutationPerformerCreateArgs = { input: PerformerCreateInput; }; export type MutationPerformerDestroyArgs = { input: PerformerDestroyInput; }; export type MutationPerformerEditArgs = { input: PerformerEditInput; }; export type MutationPerformerEditUpdateArgs = { id: Scalars['ID']['input']; input: PerformerEditInput; }; export type MutationPerformerUpdateArgs = { input: PerformerUpdateInput; }; export type MutationRegenerateApiKeyArgs = { userID?: InputMaybe; }; export type MutationRescindInviteCodeArgs = { code: Scalars['ID']['input']; }; export type MutationResetPasswordArgs = { input: ResetPasswordInput; }; export type MutationRevokeInviteArgs = { input: RevokeInviteInput; }; export type MutationSceneCreateArgs = { input: SceneCreateInput; }; export type MutationSceneDeleteFingerprintSubmissionsArgs = { input: DeleteFingerprintSubmissionsInput; }; export type MutationSceneDestroyArgs = { input: SceneDestroyInput; }; export type MutationSceneEditArgs = { input: SceneEditInput; }; export type MutationSceneEditUpdateArgs = { id: Scalars['ID']['input']; input: SceneEditInput; }; export type MutationSceneMoveFingerprintSubmissionsArgs = { input: MoveFingerprintSubmissionsInput; }; export type MutationSceneUpdateArgs = { input: SceneUpdateInput; }; export type MutationSiteCreateArgs = { input: SiteCreateInput; }; export type MutationSiteDestroyArgs = { input: SiteDestroyInput; }; export type MutationSiteUpdateArgs = { input: SiteUpdateInput; }; export type MutationStudioCreateArgs = { input: StudioCreateInput; }; export type MutationStudioDestroyArgs = { input: StudioDestroyInput; }; export type MutationStudioEditArgs = { input: StudioEditInput; }; export type MutationStudioEditUpdateArgs = { id: Scalars['ID']['input']; input: StudioEditInput; }; export type MutationStudioUpdateArgs = { input: StudioUpdateInput; }; export type MutationSubmitFingerprintArgs = { input: FingerprintSubmission; }; export type MutationSubmitFingerprintsArgs = { input: Array; }; export type MutationSubmitPerformerDraftArgs = { input: PerformerDraftInput; }; export type MutationSubmitSceneDraftArgs = { input: SceneDraftInput; }; export type MutationTagCategoryCreateArgs = { input: TagCategoryCreateInput; }; export type MutationTagCategoryDestroyArgs = { input: TagCategoryDestroyInput; }; export type MutationTagCategoryUpdateArgs = { input: TagCategoryUpdateInput; }; export type MutationTagCreateArgs = { input: TagCreateInput; }; export type MutationTagDestroyArgs = { input: TagDestroyInput; }; export type MutationTagEditArgs = { input: TagEditInput; }; export type MutationTagEditUpdateArgs = { id: Scalars['ID']['input']; input: TagEditInput; }; export type MutationTagUpdateArgs = { input: TagUpdateInput; }; export type MutationUpdateNotificationSubscriptionsArgs = { subscriptions: Array; }; export type MutationUserCreateArgs = { input: UserCreateInput; }; export type MutationUserDestroyArgs = { input: UserDestroyInput; }; export type MutationUserUpdateArgs = { input: UserUpdateInput; }; export type MutationValidateChangeEmailArgs = { email: Scalars['String']['input']; token: Scalars['ID']['input']; }; export type NewUserInput = { email: Scalars['String']['input']; invite_key?: InputMaybe; }; export type Notification = { __typename: 'Notification'; created: Scalars['Time']['output']; data: NotificationData; read: Scalars['Boolean']['output']; }; export type NotificationData = CommentCommentedEdit | CommentOwnEdit | CommentVotedEdit | DownvoteOwnEdit | FailedOwnEdit | FavoritePerformerEdit | FavoritePerformerScene | FavoriteStudioEdit | FavoriteStudioScene | FingerprintedSceneEdit | UpdatedEdit; export enum NotificationEnum { COMMENT_COMMENTED_EDIT = 'COMMENT_COMMENTED_EDIT', COMMENT_OWN_EDIT = 'COMMENT_OWN_EDIT', COMMENT_VOTED_EDIT = 'COMMENT_VOTED_EDIT', DOWNVOTE_OWN_EDIT = 'DOWNVOTE_OWN_EDIT', FAILED_OWN_EDIT = 'FAILED_OWN_EDIT', FAVORITE_PERFORMER_EDIT = 'FAVORITE_PERFORMER_EDIT', FAVORITE_PERFORMER_SCENE = 'FAVORITE_PERFORMER_SCENE', FAVORITE_STUDIO_EDIT = 'FAVORITE_STUDIO_EDIT', FAVORITE_STUDIO_SCENE = 'FAVORITE_STUDIO_SCENE', FINGERPRINTED_SCENE_EDIT = 'FINGERPRINTED_SCENE_EDIT', UPDATED_EDIT = 'UPDATED_EDIT' } export enum OperationEnum { CREATE = 'CREATE', DESTROY = 'DESTROY', MERGE = 'MERGE', MODIFY = 'MODIFY' } export type Performer = { __typename: 'Performer'; age?: Maybe; aliases: Array; band_size?: Maybe; birth_date?: Maybe; /** @deprecated Please use `birth_date` */ birthdate?: Maybe; breast_type?: Maybe; career_end_year?: Maybe; career_start_year?: Maybe; country?: Maybe; created: Scalars['Time']['output']; cup_size?: Maybe; death_date?: Maybe; deleted: Scalars['Boolean']['output']; disambiguation?: Maybe; edits: Array; ethnicity?: Maybe; eye_color?: Maybe; gender?: Maybe; hair_color?: Maybe; /** Height in cm */ height?: Maybe; hip_size?: Maybe; id: Scalars['ID']['output']; images: Array; is_favorite: Scalars['Boolean']['output']; /** @deprecated Use individual fields, cup/band/waist/hip_size */ measurements: Measurements; /** IDs of performers that were merged into this one */ merged_ids: Array; /** ID of performer that replaces this one */ merged_into_id?: Maybe; name: Scalars['String']['output']; piercings?: Maybe>; scene_count: Scalars['Int']['output']; scenes: Array; studios: Array; tattoos?: Maybe>; updated: Scalars['Time']['output']; urls: Array; waist_size?: Maybe; }; export type PerformerScenesArgs = { input?: InputMaybe; }; export type PerformerStudiosArgs = { studio_id?: InputMaybe; }; export type PerformerAppearance = { __typename: 'PerformerAppearance'; /** Performing as alias */ as?: Maybe; performer: Performer; }; export type PerformerAppearanceInput = { /** Performing as alias */ as?: InputMaybe; performer_id: Scalars['ID']['input']; }; export type PerformerCreateInput = { aliases?: InputMaybe>; band_size?: InputMaybe; birthdate?: InputMaybe; breast_type?: InputMaybe; career_end_year?: InputMaybe; career_start_year?: InputMaybe; country?: InputMaybe; cup_size?: InputMaybe; deathdate?: InputMaybe; disambiguation?: InputMaybe; draft_id?: InputMaybe; ethnicity?: InputMaybe; eye_color?: InputMaybe; gender?: InputMaybe; hair_color?: InputMaybe; height?: InputMaybe; hip_size?: InputMaybe; image_ids?: InputMaybe>; name: Scalars['String']['input']; piercings?: InputMaybe>; tattoos?: InputMaybe>; urls?: InputMaybe>; waist_size?: InputMaybe; }; export type PerformerDestroyInput = { id: Scalars['ID']['input']; }; export type PerformerDraft = { __typename: 'PerformerDraft'; aliases?: Maybe; birthdate?: Maybe; breast_type?: Maybe; career_end_year?: Maybe; career_start_year?: Maybe; country?: Maybe; deathdate?: Maybe; disambiguation?: Maybe; ethnicity?: Maybe; eye_color?: Maybe; gender?: Maybe; hair_color?: Maybe; height?: Maybe; id?: Maybe; image?: Maybe; measurements?: Maybe; name: Scalars['String']['output']; piercings?: Maybe; tattoos?: Maybe; urls?: Maybe>; }; export type PerformerDraftInput = { aliases?: InputMaybe; birthdate?: InputMaybe; breast_type?: InputMaybe; career_end_year?: InputMaybe; career_start_year?: InputMaybe; country?: InputMaybe; deathdate?: InputMaybe; disambiguation?: InputMaybe; ethnicity?: InputMaybe; eye_color?: InputMaybe; gender?: InputMaybe; hair_color?: InputMaybe; height?: InputMaybe; id?: InputMaybe; image?: InputMaybe; measurements?: InputMaybe; name: Scalars['String']['input']; piercings?: InputMaybe; tattoos?: InputMaybe; urls?: InputMaybe>; }; export type PerformerEdit = { __typename: 'PerformerEdit'; added_aliases?: Maybe>; added_images?: Maybe>; added_piercings?: Maybe>; added_tattoos?: Maybe>; added_urls?: Maybe>; aliases: Array; band_size?: Maybe; birthdate?: Maybe; breast_type?: Maybe; career_end_year?: Maybe; career_start_year?: Maybe; country?: Maybe; cup_size?: Maybe; deathdate?: Maybe; disambiguation?: Maybe; draft_id?: Maybe; ethnicity?: Maybe; eye_color?: Maybe; gender?: Maybe; hair_color?: Maybe; /** Height in cm */ height?: Maybe; hip_size?: Maybe; images: Array; name?: Maybe; piercings: Array; removed_aliases?: Maybe>; removed_images?: Maybe>; removed_piercings?: Maybe>; removed_tattoos?: Maybe>; removed_urls?: Maybe>; tattoos: Array; urls: Array; waist_size?: Maybe; }; export type PerformerEditDetailsInput = { aliases?: InputMaybe>; band_size?: InputMaybe; birthdate?: InputMaybe; breast_type?: InputMaybe; career_end_year?: InputMaybe; career_start_year?: InputMaybe; country?: InputMaybe; cup_size?: InputMaybe; deathdate?: InputMaybe; disambiguation?: InputMaybe; draft_id?: InputMaybe; ethnicity?: InputMaybe; eye_color?: InputMaybe; gender?: InputMaybe; hair_color?: InputMaybe; height?: InputMaybe; hip_size?: InputMaybe; image_ids?: InputMaybe>; name?: InputMaybe; piercings?: InputMaybe>; tattoos?: InputMaybe>; urls?: InputMaybe>; waist_size?: InputMaybe; }; export type PerformerEditInput = { /** Not required for destroy type */ details?: InputMaybe; edit: EditInput; /** Controls aliases modification for merges and name modifications */ options?: InputMaybe; }; export type PerformerEditOptions = { __typename: 'PerformerEditOptions'; /** Set performer alias on scenes attached to merge sources to old name */ set_merge_aliases: Scalars['Boolean']['output']; /** Set performer alias on scenes without alias to old name if name is changed */ set_modify_aliases: Scalars['Boolean']['output']; }; export type PerformerEditOptionsInput = { /** Set performer alias on scenes attached to merge sources to old name */ set_merge_aliases?: InputMaybe; /** Set performer alias on scenes without alias to old name if name is changed */ set_modify_aliases?: InputMaybe; }; export type PerformerQueryInput = { age?: InputMaybe; /** Search aliases only - assumes like query unless quoted */ alias?: InputMaybe; band_size?: InputMaybe; birth_year?: InputMaybe; birthdate?: InputMaybe; breast_type?: InputMaybe; career_end_year?: InputMaybe; career_start_year?: InputMaybe; country?: InputMaybe; cup_size?: InputMaybe; deathdate?: InputMaybe; direction?: SortDirectionEnum; disambiguation?: InputMaybe; ethnicity?: InputMaybe; eye_color?: InputMaybe; gender?: InputMaybe; hair_color?: InputMaybe; height?: InputMaybe; hip_size?: InputMaybe; /** Filter by performerfavorite status for the current user */ is_favorite?: InputMaybe; /** Searches name only - assumes like query unless quoted */ name?: InputMaybe; /** Searches name and disambiguation - assumes like query unless quoted */ names?: InputMaybe; page?: Scalars['Int']['input']; per_page?: Scalars['Int']['input']; /** Filter by a performer they have performed in scenes with */ performed_with?: InputMaybe; piercings?: InputMaybe; sort?: PerformerSortEnum; /** Filter by a studio */ studio_id?: InputMaybe; tattoos?: InputMaybe; /** Filter to search urls - assumes like query unless quoted */ url?: InputMaybe; waist_size?: InputMaybe; }; export type PerformerScenesInput = { /** Filter by another performer that also performs in the scenes */ performed_with?: InputMaybe; /** Filter by a studio */ studio_id?: InputMaybe; /** Filter by tags */ tags?: InputMaybe; }; export type PerformerSearchFacets = { __typename: 'PerformerSearchFacets'; genders: Array; }; export type PerformerSearchFilter = { /** Filter by gender */ gender?: InputMaybe; }; export enum PerformerSortEnum { BIRTHDATE = 'BIRTHDATE', CAREER_START_YEAR = 'CAREER_START_YEAR', CREATED_AT = 'CREATED_AT', DEATHDATE = 'DEATHDATE', DEBUT = 'DEBUT', LAST_SCENE = 'LAST_SCENE', NAME = 'NAME', SCENE_COUNT = 'SCENE_COUNT', UPDATED_AT = 'UPDATED_AT' } export type PerformerStudio = { __typename: 'PerformerStudio'; scene_count: Scalars['Int']['output']; studio: Studio; }; export type PerformerUpdateInput = { aliases?: InputMaybe>; band_size?: InputMaybe; birthdate?: InputMaybe; breast_type?: InputMaybe; career_end_year?: InputMaybe; career_start_year?: InputMaybe; country?: InputMaybe; cup_size?: InputMaybe; deathdate?: InputMaybe; disambiguation?: InputMaybe; ethnicity?: InputMaybe; eye_color?: InputMaybe; gender?: InputMaybe; hair_color?: InputMaybe; height?: InputMaybe; hip_size?: InputMaybe; id: Scalars['ID']['input']; image_ids?: InputMaybe>; name?: InputMaybe; piercings?: InputMaybe>; tattoos?: InputMaybe>; urls?: InputMaybe>; waist_size?: InputMaybe; }; /** The query root for this schema */ export type Query = { __typename: 'Query'; findDraft?: Maybe; findDrafts: Array; findEdit?: Maybe; /** Find a performer by ID */ findPerformer?: Maybe; /** Find a scene by ID */ findScene?: Maybe; /** Finds scenes that match a list of hashes */ findScenesBySceneFingerprints: Array>>; /** Find an external site by ID */ findSite?: Maybe; /** Find a studio by ID or name */ findStudio?: Maybe; /** Find a tag by ID or name */ findTag?: Maybe; /** Find a tag category by ID */ findTagCategory?: Maybe; /** Find a tag with a matching name or alias */ findTagOrAlias?: Maybe; /** Find user by ID or username */ findUser?: Maybe; getConfig: StashBoxConfig; getUnreadNotificationCount: Scalars['Int']['output']; /** Returns currently authenticated user */ me?: Maybe; queryEdits: QueryEditsResultType; queryExistingPerformer: QueryExistingPerformerResult; queryExistingScene: QueryExistingSceneResult; queryModAudits: QueryModAuditsResultType; queryNotifications: QueryNotificationsResult; queryPerformers: QueryPerformersResultType; queryScenes: QueryScenesResultType; querySites: QuerySitesResultType; queryStudios: QueryStudiosResultType; queryTagCategories: QueryTagCategoriesResultType; queryTags: QueryTagsResultType; queryUsers: QueryUsersResultType; /** @deprecated Use searchPerformers */ searchPerformer: Array; searchPerformers: QueryPerformersResultType; /** @deprecated Use searchScenes */ searchScene: Array; searchScenes: QueryScenesResultType; searchStudio: Array; searchTag: Array; version: Version; }; /** The query root for this schema */ export type QueryFindDraftArgs = { id: Scalars['ID']['input']; }; /** The query root for this schema */ export type QueryFindEditArgs = { id: Scalars['ID']['input']; }; /** The query root for this schema */ export type QueryFindPerformerArgs = { id: Scalars['ID']['input']; }; /** The query root for this schema */ export type QueryFindSceneArgs = { id: Scalars['ID']['input']; }; /** The query root for this schema */ export type QueryFindScenesBySceneFingerprintsArgs = { fingerprints: Array>; }; /** The query root for this schema */ export type QueryFindSiteArgs = { id: Scalars['ID']['input']; }; /** The query root for this schema */ export type QueryFindStudioArgs = { id?: InputMaybe; name?: InputMaybe; }; /** The query root for this schema */ export type QueryFindTagArgs = { id?: InputMaybe; name?: InputMaybe; }; /** The query root for this schema */ export type QueryFindTagCategoryArgs = { id: Scalars['ID']['input']; }; /** The query root for this schema */ export type QueryFindTagOrAliasArgs = { name: Scalars['String']['input']; }; /** The query root for this schema */ export type QueryFindUserArgs = { id?: InputMaybe; username?: InputMaybe; }; /** The query root for this schema */ export type QueryQueryEditsArgs = { input: EditQueryInput; }; /** The query root for this schema */ export type QueryQueryExistingPerformerArgs = { input: QueryExistingPerformerInput; }; /** The query root for this schema */ export type QueryQueryExistingSceneArgs = { input: QueryExistingSceneInput; }; /** The query root for this schema */ export type QueryQueryModAuditsArgs = { input: ModAuditQueryInput; }; /** The query root for this schema */ export type QueryQueryNotificationsArgs = { input: QueryNotificationsInput; }; /** The query root for this schema */ export type QueryQueryPerformersArgs = { input: PerformerQueryInput; }; /** The query root for this schema */ export type QueryQueryScenesArgs = { input: SceneQueryInput; }; /** The query root for this schema */ export type QueryQueryStudiosArgs = { input: StudioQueryInput; }; /** The query root for this schema */ export type QueryQueryTagsArgs = { input: TagQueryInput; }; /** The query root for this schema */ export type QueryQueryUsersArgs = { input: UserQueryInput; }; /** The query root for this schema */ export type QuerySearchPerformerArgs = { limit?: InputMaybe; term: Scalars['String']['input']; }; /** The query root for this schema */ export type QuerySearchPerformersArgs = { filter?: InputMaybe; limit?: InputMaybe; page?: InputMaybe; per_page?: InputMaybe; term: Scalars['String']['input']; }; /** The query root for this schema */ export type QuerySearchSceneArgs = { limit?: InputMaybe; term: Scalars['String']['input']; }; /** The query root for this schema */ export type QuerySearchScenesArgs = { limit?: InputMaybe; page?: InputMaybe; per_page?: InputMaybe; term: Scalars['String']['input']; }; /** The query root for this schema */ export type QuerySearchStudioArgs = { limit?: InputMaybe; term: Scalars['String']['input']; }; /** The query root for this schema */ export type QuerySearchTagArgs = { limit?: InputMaybe; term: Scalars['String']['input']; }; export type QueryEditsResultType = { __typename: 'QueryEditsResultType'; count: Scalars['Int']['output']; edits: Array; }; export type QueryExistingPerformerInput = { disambiguation?: InputMaybe; name?: InputMaybe; urls: Array; }; export type QueryExistingPerformerResult = { __typename: 'QueryExistingPerformerResult'; edits: Array; performers: Array; }; export type QueryExistingSceneInput = { fingerprints: Array; studio_id?: InputMaybe; title?: InputMaybe; }; export type QueryExistingSceneResult = { __typename: 'QueryExistingSceneResult'; edits: Array; scenes: Array; }; export type QueryModAuditsResultType = { __typename: 'QueryModAuditsResultType'; audits: Array; count: Scalars['Int']['output']; }; export type QueryNotificationsInput = { page?: Scalars['Int']['input']; per_page?: Scalars['Int']['input']; type?: InputMaybe; unread_only?: InputMaybe; }; export type QueryNotificationsResult = { __typename: 'QueryNotificationsResult'; count: Scalars['Int']['output']; notifications: Array; }; export type QueryPerformersResultType = { __typename: 'QueryPerformersResultType'; count: Scalars['Int']['output']; /** Search facets, only available for searchPerformer queries */ facets?: Maybe; performers: Array; }; export type QueryScenesResultType = { __typename: 'QueryScenesResultType'; count: Scalars['Int']['output']; scenes: Array; }; export type QuerySitesResultType = { __typename: 'QuerySitesResultType'; count: Scalars['Int']['output']; sites: Array; }; export type QueryStudiosResultType = { __typename: 'QueryStudiosResultType'; count: Scalars['Int']['output']; studios: Array; }; export type QueryTagCategoriesResultType = { __typename: 'QueryTagCategoriesResultType'; count: Scalars['Int']['output']; tag_categories: Array; }; export type QueryTagsResultType = { __typename: 'QueryTagsResultType'; count: Scalars['Int']['output']; tags: Array; }; export type QueryUsersResultType = { __typename: 'QueryUsersResultType'; count: Scalars['Int']['output']; users: Array; }; export type ResetPasswordInput = { email: Scalars['String']['input']; }; export type RevokeInviteInput = { amount: Scalars['Int']['input']; user_id: Scalars['ID']['input']; }; export type RoleCriterionInput = { modifier: CriterionModifier; value: Array; }; export enum RoleEnum { ADMIN = 'ADMIN', BOT = 'BOT', EDIT = 'EDIT', EDIT_TAGS = 'EDIT_TAGS', /** May generate invites without tokens */ INVITE = 'INVITE', /** May grant and rescind invite tokens and resind invite keys */ MANAGE_INVITES = 'MANAGE_INVITES', MODERATE = 'MODERATE', MODIFY = 'MODIFY', READ = 'READ', READ_ONLY = 'READ_ONLY', VOTE = 'VOTE' } export type Scene = { __typename: 'Scene'; code?: Maybe; created: Scalars['Time']['output']; /** @deprecated Please use `release_date` instead */ date?: Maybe; deleted: Scalars['Boolean']['output']; details?: Maybe; director?: Maybe; duration?: Maybe; edits: Array; fingerprints: Array; id: Scalars['ID']['output']; images: Array; performers: Array; production_date?: Maybe; release_date?: Maybe; studio?: Maybe; tags: Array; title?: Maybe; updated: Scalars['Time']['output']; urls: Array; }; export type SceneFingerprintsArgs = { is_submitted?: InputMaybe; }; export type SceneCreateInput = { code?: InputMaybe; date: Scalars['String']['input']; details?: InputMaybe; director?: InputMaybe; duration?: InputMaybe; fingerprints: Array; image_ids?: InputMaybe>; performers?: InputMaybe>; production_date?: InputMaybe; studio_id?: InputMaybe; tag_ids?: InputMaybe>; title?: InputMaybe; urls?: InputMaybe>; }; export type SceneDestroyInput = { id: Scalars['ID']['input']; }; export type SceneDraft = { __typename: 'SceneDraft'; code?: Maybe; date?: Maybe; details?: Maybe; director?: Maybe; fingerprints: Array; id?: Maybe; image?: Maybe; performers: Array; production_date?: Maybe; studio?: Maybe; tags?: Maybe>; title?: Maybe; urls?: Maybe>; }; export type SceneDraftInput = { code?: InputMaybe; date?: InputMaybe; details?: InputMaybe; director?: InputMaybe; fingerprints: Array; id?: InputMaybe; image?: InputMaybe; performers: Array; production_date?: InputMaybe; studio?: InputMaybe; tags?: InputMaybe>; title?: InputMaybe; /** @deprecated Use urls field instead. */ url?: InputMaybe; urls?: InputMaybe>; }; export type SceneDraftPerformer = DraftEntity | Performer; export type SceneDraftStudio = DraftEntity | Studio; export type SceneDraftTag = DraftEntity | Tag; export type SceneEdit = { __typename: 'SceneEdit'; added_fingerprints?: Maybe>; added_images?: Maybe>; /** Added or modified performer appearance entries */ added_performers?: Maybe>; added_tags?: Maybe>; added_urls?: Maybe>; code?: Maybe; date?: Maybe; details?: Maybe; director?: Maybe; draft_id?: Maybe; duration?: Maybe; fingerprints: Array; images: Array; performers: Array; production_date?: Maybe; removed_fingerprints?: Maybe>; removed_images?: Maybe>; removed_performers?: Maybe>; removed_tags?: Maybe>; removed_urls?: Maybe>; studio?: Maybe; tags: Array; title?: Maybe; urls: Array; }; export type SceneEditDetailsInput = { code?: InputMaybe; date?: InputMaybe; details?: InputMaybe; director?: InputMaybe; draft_id?: InputMaybe; duration?: InputMaybe; fingerprints?: InputMaybe>; image_ids?: InputMaybe>; performers?: InputMaybe>; production_date?: InputMaybe; studio_id?: InputMaybe; tag_ids?: InputMaybe>; title?: InputMaybe; urls?: InputMaybe>; }; export type SceneEditInput = { /** Not required for destroy type */ details?: InputMaybe; edit: EditInput; }; export type SceneQueryInput = { /** Filter to include scenes with performer appearing as alias */ alias?: InputMaybe; /** Filter by date */ date?: InputMaybe; direction?: SortDirectionEnum; /** Filter by favorited entity */ favorites?: InputMaybe; /** Filter to only include scenes with these fingerprints */ fingerprints?: InputMaybe; /** Filter to scenes with fingerprints submitted by the user */ has_fingerprint_submissions?: InputMaybe; page?: Scalars['Int']['input']; /** Filter to only include scenes with this studio as primary or parent */ parentStudio?: InputMaybe; per_page?: Scalars['Int']['input']; /** Filter to only include scenes with these performers */ performers?: InputMaybe; /** Filter by production date */ production_date?: InputMaybe; sort?: SceneSortEnum; /** Filter to only include scenes with this studio */ studios?: InputMaybe; /** Filter to only include scenes with these tags */ tags?: InputMaybe; /** Filter to search title and details - assumes like query unless quoted */ text?: InputMaybe; /** Filter to search title - assumes like query unless quoted */ title?: InputMaybe; /** Filter to search urls - assumes like query unless quoted */ url?: InputMaybe; }; export enum SceneSortEnum { CREATED_AT = 'CREATED_AT', DATE = 'DATE', TITLE = 'TITLE', TRENDING = 'TRENDING', UPDATED_AT = 'UPDATED_AT' } export type SceneUpdateInput = { code?: InputMaybe; date?: InputMaybe; details?: InputMaybe; director?: InputMaybe; duration?: InputMaybe; fingerprints?: InputMaybe>; id: Scalars['ID']['input']; image_ids?: InputMaybe>; performers?: InputMaybe>; production_date?: InputMaybe; studio_id?: InputMaybe; tag_ids?: InputMaybe>; title?: InputMaybe; urls?: InputMaybe>; }; export type Site = { __typename: 'Site'; created: Scalars['Time']['output']; description?: Maybe; icon: Scalars['String']['output']; id: Scalars['ID']['output']; name: Scalars['String']['output']; regex?: Maybe; updated: Scalars['Time']['output']; url?: Maybe; valid_types: Array; }; export type SiteCreateInput = { description?: InputMaybe; name: Scalars['String']['input']; regex?: InputMaybe; url?: InputMaybe; valid_types: Array; }; export type SiteDestroyInput = { id: Scalars['ID']['input']; }; export type SiteUpdateInput = { description?: InputMaybe; id: Scalars['ID']['input']; name: Scalars['String']['input']; regex?: InputMaybe; url?: InputMaybe; valid_types: Array; }; export enum SortDirectionEnum { ASC = 'ASC', DESC = 'DESC' } export type StashBoxConfig = { __typename: 'StashBoxConfig'; edit_update_limit: Scalars['Int']['output']; guidelines_url: Scalars['String']['output']; host_url: Scalars['String']['output']; min_destructive_voting_period: Scalars['Int']['output']; require_activation: Scalars['Boolean']['output']; require_invite: Scalars['Boolean']['output']; require_scene_draft: Scalars['Boolean']['output']; require_tag_role: Scalars['Boolean']['output']; vote_application_threshold: Scalars['Int']['output']; vote_cron_interval: Scalars['String']['output']; vote_promotion_threshold?: Maybe; voting_period: Scalars['Int']['output']; }; export type StringCriterionInput = { modifier: CriterionModifier; value: Scalars['String']['input']; }; export type Studio = { __typename: 'Studio'; aliases: Array; /** @deprecated Use sub_studios instead */ child_studios: Array; created: Scalars['Time']['output']; deleted: Scalars['Boolean']['output']; id: Scalars['ID']['output']; images: Array; is_favorite: Scalars['Boolean']['output']; name: Scalars['String']['output']; parent?: Maybe; performers: QueryPerformersResultType; sub_studios: QueryStudiosResultType; updated: Scalars['Time']['output']; urls: Array; }; export type StudioPerformersArgs = { input: PerformerQueryInput; }; export type StudioSub_StudiosArgs = { input?: InputMaybe; }; export type StudioCreateInput = { aliases?: InputMaybe>; image_ids?: InputMaybe>; name: Scalars['String']['input']; parent_id?: InputMaybe; urls?: InputMaybe>; }; export type StudioDestroyInput = { id: Scalars['ID']['input']; }; export type StudioEdit = { __typename: 'StudioEdit'; added_aliases?: Maybe>; added_images?: Maybe>; /** Added and modified URLs */ added_urls?: Maybe>; images: Array; name?: Maybe; parent?: Maybe; removed_aliases?: Maybe>; removed_images?: Maybe>; removed_urls?: Maybe>; urls: Array; }; export type StudioEditDetailsInput = { aliases?: InputMaybe>; image_ids?: InputMaybe>; name?: InputMaybe; parent_id?: InputMaybe; urls?: InputMaybe>; }; export type StudioEditInput = { /** Not required for destroy type */ details?: InputMaybe; edit: EditInput; }; export type StudioQueryInput = { direction?: SortDirectionEnum; has_parent?: InputMaybe; /** Filter by studio favorite status for the current user */ is_favorite?: InputMaybe; /** Filter to search name - assumes like query unless quoted */ name?: InputMaybe; /** Filter to search studio name, aliases and parent studio name - assumes like query unless quoted */ names?: InputMaybe; page?: Scalars['Int']['input']; parent?: InputMaybe; per_page?: Scalars['Int']['input']; sort?: StudioSortEnum; /** Filter to search url - assumes like query unless quoted */ url?: InputMaybe; }; export enum StudioSortEnum { CREATED_AT = 'CREATED_AT', NAME = 'NAME', UPDATED_AT = 'UPDATED_AT' } export type StudioUpdateInput = { aliases?: InputMaybe>; id: Scalars['ID']['input']; image_ids?: InputMaybe>; name?: InputMaybe; parent_id?: InputMaybe; urls?: InputMaybe>; }; export type Tag = { __typename: 'Tag'; aliases: Array; category?: Maybe; created: Scalars['Time']['output']; deleted: Scalars['Boolean']['output']; description?: Maybe; edits: Array; id: Scalars['ID']['output']; name: Scalars['String']['output']; updated: Scalars['Time']['output']; }; export type TagCategory = { __typename: 'TagCategory'; description?: Maybe; group: TagGroupEnum; id: Scalars['ID']['output']; name: Scalars['String']['output']; }; export type TagCategoryCreateInput = { description?: InputMaybe; group: TagGroupEnum; name: Scalars['String']['input']; }; export type TagCategoryDestroyInput = { id: Scalars['ID']['input']; }; export type TagCategoryUpdateInput = { description?: InputMaybe; group?: InputMaybe; id: Scalars['ID']['input']; name?: InputMaybe; }; export type TagCreateInput = { aliases?: InputMaybe>; category_id?: InputMaybe; description?: InputMaybe; name: Scalars['String']['input']; }; export type TagDestroyInput = { id: Scalars['ID']['input']; }; export type TagEdit = { __typename: 'TagEdit'; added_aliases?: Maybe>; aliases: Array; category?: Maybe; description?: Maybe; name?: Maybe; removed_aliases?: Maybe>; }; export type TagEditDetailsInput = { aliases?: InputMaybe>; category_id?: InputMaybe; description?: InputMaybe; name?: InputMaybe; }; export type TagEditInput = { /** Not required for destroy type */ details?: InputMaybe; edit: EditInput; }; export enum TagGroupEnum { ACTION = 'ACTION', PEOPLE = 'PEOPLE', SCENE = 'SCENE' } export type TagQueryInput = { /** Filter to category ID */ category_id?: InputMaybe; direction?: SortDirectionEnum; /** Filter to search name - assumes like query unless quoted */ name?: InputMaybe; /** Searches name and aliases - assumes like query unless quoted */ names?: InputMaybe; page?: Scalars['Int']['input']; per_page?: Scalars['Int']['input']; sort?: TagSortEnum; /** Filter to search name, aliases and description - assumes like query unless quoted */ text?: InputMaybe; }; export enum TagSortEnum { CREATED_AT = 'CREATED_AT', NAME = 'NAME', UPDATED_AT = 'UPDATED_AT' } export type TagUpdateInput = { aliases?: InputMaybe>; category_id?: InputMaybe; description?: InputMaybe; id: Scalars['ID']['input']; name?: InputMaybe; }; export enum TargetTypeEnum { PERFORMER = 'PERFORMER', SCENE = 'SCENE', STUDIO = 'STUDIO', TAG = 'TAG' } export type Url = { __typename: 'URL'; site: Site; /** @deprecated Use the site field instead */ type: Scalars['String']['output']; url: Scalars['String']['output']; }; export type UrlInput = { site_id: Scalars['ID']['input']; url: Scalars['String']['input']; }; export type UpdatedEdit = { __typename: 'UpdatedEdit'; edit: Edit; }; export type User = { __typename: 'User'; /** @deprecated Use invite_codes instead */ active_invite_codes?: Maybe>; /** Calls to the API from this user over a configurable time period */ api_calls: Scalars['Int']['output']; /** Should not be visible to other users */ api_key?: Maybe; /** Edit counts by status */ edit_count: UserEditCount; /** Should not be visible to other users */ email?: Maybe; id: Scalars['ID']['output']; invite_codes?: Maybe>; invite_tokens?: Maybe; invited_by?: Maybe; name: Scalars['String']['output']; notification_subscriptions: Array; /** Should not be visible to other users */ roles?: Maybe>; /** Vote counts by type */ vote_count: UserVoteCount; }; export type UserChangeEmailInput = { existing_email_token?: InputMaybe; new_email?: InputMaybe; new_email_token?: InputMaybe; }; export enum UserChangeEmailStatus { CONFIRM_NEW = 'CONFIRM_NEW', CONFIRM_OLD = 'CONFIRM_OLD', ERROR = 'ERROR', EXPIRED = 'EXPIRED', INVALID_TOKEN = 'INVALID_TOKEN', SUCCESS = 'SUCCESS' } export type UserChangePasswordInput = { /** Password in plain text */ existing_password?: InputMaybe; new_password: Scalars['String']['input']; reset_key?: InputMaybe; }; export type UserCreateInput = { email: Scalars['String']['input']; invited_by_id?: InputMaybe; name: Scalars['String']['input']; /** Password in plain text */ password: Scalars['String']['input']; roles: Array; }; export type UserDestroyInput = { id: Scalars['ID']['input']; }; export type UserEditCount = { __typename: 'UserEditCount'; accepted: Scalars['Int']['output']; canceled: Scalars['Int']['output']; failed: Scalars['Int']['output']; immediate_accepted: Scalars['Int']['output']; immediate_rejected: Scalars['Int']['output']; pending: Scalars['Int']['output']; rejected: Scalars['Int']['output']; }; export type UserQueryInput = { /** Filter by api key */ apiKey?: InputMaybe; /** Filter by number of API calls */ api_calls?: InputMaybe; /** Filter to search email - assumes like query unless quoted */ email?: InputMaybe; /** Filter by user that invited */ invited_by?: InputMaybe; /** Filter to search user name - assumes like query unless quoted */ name?: InputMaybe; page?: Scalars['Int']['input']; per_page?: Scalars['Int']['input']; /** Filter by roles */ roles?: InputMaybe; /** Filter by successful edits */ successful_edits?: InputMaybe; /** Filter by votes on successful edits */ successful_votes?: InputMaybe; /** Filter by unsuccessful edits */ unsuccessful_edits?: InputMaybe; /** Filter by votes on unsuccessful edits */ unsuccessful_votes?: InputMaybe; }; export type UserUpdateInput = { email?: InputMaybe; id: Scalars['ID']['input']; name?: InputMaybe; /** Password in plain text */ password?: InputMaybe; roles?: InputMaybe>; }; export type UserVoteCount = { __typename: 'UserVoteCount'; abstain: Scalars['Int']['output']; accept: Scalars['Int']['output']; immediate_accept: Scalars['Int']['output']; immediate_reject: Scalars['Int']['output']; reject: Scalars['Int']['output']; }; export enum UserVotedFilterEnum { ABSTAIN = 'ABSTAIN', ACCEPT = 'ACCEPT', NOT_VOTED = 'NOT_VOTED', REJECT = 'REJECT' } export enum ValidSiteTypeEnum { PERFORMER = 'PERFORMER', SCENE = 'SCENE', STUDIO = 'STUDIO' } export type Version = { __typename: 'Version'; build_time: Scalars['String']['output']; build_type: Scalars['String']['output']; hash: Scalars['String']['output']; version: Scalars['String']['output']; }; export enum VoteStatusEnum { ACCEPTED = 'ACCEPTED', CANCELED = 'CANCELED', FAILED = 'FAILED', IMMEDIATE_ACCEPTED = 'IMMEDIATE_ACCEPTED', IMMEDIATE_REJECTED = 'IMMEDIATE_REJECTED', PENDING = 'PENDING', REJECTED = 'REJECTED' } export enum VoteTypeEnum { ABSTAIN = 'ABSTAIN', ACCEPT = 'ACCEPT', /** Immediately accepts the edit - bypassing the vote */ IMMEDIATE_ACCEPT = 'IMMEDIATE_ACCEPT', /** Immediately rejects the edit - bypassing the vote */ IMMEDIATE_REJECT = 'IMMEDIATE_REJECT', REJECT = 'REJECT' } export type CommentFragment = { __typename: 'EditComment', id: string, date: string, comment: string, user?: { __typename: 'User', id: string, name: string } | null }; export type EditFragment = { __typename: 'Edit', id: string, target_type: TargetTypeEnum, operation: OperationEnum, status: VoteStatusEnum, bot: boolean, applied: boolean, created: string, updated?: string | null, closed?: string | null, expires?: string | null, update_count: number, updatable: boolean, vote_count: number, destructive: boolean, comments: Array<{ __typename: 'EditComment', id: string, date: string, comment: string, user?: { __typename: 'User', id: string, name: string } | null }>, votes: Array<{ __typename: 'EditVote', date: string, vote: VoteTypeEnum, user?: { __typename: 'User', id: string, name: string } | null }>, user?: { __typename: 'User', id: string, name: string } | null, target?: | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, added_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, old_details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, merge_sources: Array< | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } >, options?: { __typename: 'PerformerEditOptions', set_modify_aliases: boolean, set_merge_aliases: boolean } | null }; export type FingerprintFragment = { __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }; export type ImageFragment = { __typename: 'Image', id: string, url: string, width: number, height: number }; export type PerformerFragment = { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> }; export type QuerySceneFragment = { __typename: 'Scene', id: string, release_date?: string | null, title?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }> }; export type SceneFragment = { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> }; export type ScenePerformerFragment = { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array }; export type SearchPerformerFragment = { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array, country?: string | null, career_start_year?: number | null, career_end_year?: number | null, scene_count: number, birth_date?: string | null, is_favorite: boolean, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> }; export type StudioFragment = { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> }; export type TagFragment = { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }; export type UrlFragment = { __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }; export type ActivateNewUserMutationVariables = Exact<{ input: ActivateNewUserInput; }>; export type ActivateNewUserMutation = { __typename: 'Mutation', activateNewUser?: { __typename: 'User', id: string } | null }; export type AddImageMutationVariables = Exact<{ imageData: ImageCreateInput; }>; export type AddImageMutation = { __typename: 'Mutation', imageCreate?: { __typename: 'Image', id: string, url: string, width: number, height: number } | null }; export type AddSceneMutationVariables = Exact<{ sceneData: SceneCreateInput; }>; export type AddSceneMutation = { __typename: 'Mutation', sceneCreate?: { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, code?: string | null, details?: string | null, director?: string | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string } }>, studio?: { __typename: 'Studio', id: string, name: string } | null, performers: Array<{ __typename: 'PerformerAppearance', performer: { __typename: 'Performer', name: string, id: string, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null }> } | null }; export type AddSiteMutationVariables = Exact<{ siteData: SiteCreateInput; }>; export type AddSiteMutation = { __typename: 'Mutation', siteCreate?: { __typename: 'Site', id: string, name: string, description?: string | null, url?: string | null, regex?: string | null, valid_types: Array } | null }; export type AddStudioMutationVariables = Exact<{ studioData: StudioCreateInput; }>; export type AddStudioMutation = { __typename: 'Mutation', studioCreate?: { __typename: 'Studio', id: string, name: string, aliases: Array, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string } }> } | null }; export type AddTagCategoryMutationVariables = Exact<{ categoryData: TagCategoryCreateInput; }>; export type AddTagCategoryMutation = { __typename: 'Mutation', tagCategoryCreate?: { __typename: 'TagCategory', id: string, name: string, description?: string | null, group: TagGroupEnum } | null }; export type AddUserMutationVariables = Exact<{ userData: UserCreateInput; }>; export type AddUserMutation = { __typename: 'Mutation', userCreate?: { __typename: 'User', id: string, name: string, email?: string | null, roles?: Array | null } | null }; export type AmendEditMutationVariables = Exact<{ input: AmendEditInput; }>; export type AmendEditMutation = { __typename: 'Mutation', amendEdit: { __typename: 'Edit', id: string, target_type: TargetTypeEnum, operation: OperationEnum, status: VoteStatusEnum, bot: boolean, applied: boolean, created: string, updated?: string | null, closed?: string | null, expires?: string | null, update_count: number, updatable: boolean, vote_count: number, destructive: boolean, comments: Array<{ __typename: 'EditComment', id: string, date: string, comment: string, user?: { __typename: 'User', id: string, name: string } | null }>, votes: Array<{ __typename: 'EditVote', date: string, vote: VoteTypeEnum, user?: { __typename: 'User', id: string, name: string } | null }>, user?: { __typename: 'User', id: string, name: string } | null, target?: | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, added_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, old_details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, merge_sources: Array< | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } >, options?: { __typename: 'PerformerEditOptions', set_modify_aliases: boolean, set_merge_aliases: boolean } | null } }; export type ApplyEditMutationVariables = Exact<{ input: ApplyEditInput; }>; export type ApplyEditMutation = { __typename: 'Mutation', applyEdit: { __typename: 'Edit', id: string, target_type: TargetTypeEnum, operation: OperationEnum, status: VoteStatusEnum, bot: boolean, applied: boolean, created: string, updated?: string | null, closed?: string | null, expires?: string | null, update_count: number, updatable: boolean, vote_count: number, destructive: boolean, comments: Array<{ __typename: 'EditComment', id: string, date: string, comment: string, user?: { __typename: 'User', id: string, name: string } | null }>, votes: Array<{ __typename: 'EditVote', date: string, vote: VoteTypeEnum, user?: { __typename: 'User', id: string, name: string } | null }>, user?: { __typename: 'User', id: string, name: string } | null, target?: | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, added_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, old_details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, merge_sources: Array< | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } >, options?: { __typename: 'PerformerEditOptions', set_modify_aliases: boolean, set_merge_aliases: boolean } | null } }; export type CancelEditMutationVariables = Exact<{ input: CancelEditInput; }>; export type CancelEditMutation = { __typename: 'Mutation', cancelEdit: { __typename: 'Edit', id: string, target_type: TargetTypeEnum, operation: OperationEnum, status: VoteStatusEnum, applied: boolean, created: string, user?: { __typename: 'User', id: string, name: string } | null, target?: | { __typename: 'Performer' } | { __typename: 'Scene' } | { __typename: 'Studio' } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean } | null, details?: | { __typename: 'PerformerEdit' } | { __typename: 'SceneEdit' } | { __typename: 'StudioEdit' } | { __typename: 'TagEdit', name?: string | null, description?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null } | null, merge_sources: Array< | { __typename: 'Performer' } | { __typename: 'Scene' } | { __typename: 'Studio' } | { __typename: 'Tag', id: string, name: string, description?: string | null } > } }; export type ChangePasswordMutationVariables = Exact<{ userData: UserChangePasswordInput; }>; export type ChangePasswordMutation = { __typename: 'Mutation', changePassword: boolean }; export type ConfirmChangeEmailMutationVariables = Exact<{ token: Scalars['ID']['input']; }>; export type ConfirmChangeEmailMutation = { __typename: 'Mutation', confirmChangeEmail: UserChangeEmailStatus }; export type DeleteDraftMutationVariables = Exact<{ id: Scalars['ID']['input']; }>; export type DeleteDraftMutation = { __typename: 'Mutation', destroyDraft: boolean }; export type DeleteEditMutationVariables = Exact<{ input: DeleteEditInput; }>; export type DeleteEditMutation = { __typename: 'Mutation', deleteEdit: boolean }; export type DeleteFingerprintSubmissionsMutationVariables = Exact<{ input: DeleteFingerprintSubmissionsInput; }>; export type DeleteFingerprintSubmissionsMutation = { __typename: 'Mutation', sceneDeleteFingerprintSubmissions: boolean }; export type DeleteSceneMutationVariables = Exact<{ input: SceneDestroyInput; }>; export type DeleteSceneMutation = { __typename: 'Mutation', sceneDestroy: boolean }; export type DeleteSiteMutationVariables = Exact<{ input: SiteDestroyInput; }>; export type DeleteSiteMutation = { __typename: 'Mutation', siteDestroy: boolean }; export type DeleteStudioMutationVariables = Exact<{ input: StudioDestroyInput; }>; export type DeleteStudioMutation = { __typename: 'Mutation', studioDestroy: boolean }; export type DeleteTagCategoryMutationVariables = Exact<{ input: TagCategoryDestroyInput; }>; export type DeleteTagCategoryMutation = { __typename: 'Mutation', tagCategoryDestroy: boolean }; export type DeleteUserMutationVariables = Exact<{ input: UserDestroyInput; }>; export type DeleteUserMutation = { __typename: 'Mutation', userDestroy: boolean }; export type EditCommentMutationVariables = Exact<{ input: EditCommentInput; }>; export type EditCommentMutation = { __typename: 'Mutation', editComment: { __typename: 'Edit', id: string, comments: Array<{ __typename: 'EditComment', id: string, date: string, comment: string, user?: { __typename: 'User', id: string, name: string } | null }> } }; export type FavoritePerformerMutationVariables = Exact<{ id: Scalars['ID']['input']; favorite: Scalars['Boolean']['input']; }>; export type FavoritePerformerMutation = { __typename: 'Mutation', favoritePerformer: boolean }; export type FavoriteStudioMutationVariables = Exact<{ id: Scalars['ID']['input']; favorite: Scalars['Boolean']['input']; }>; export type FavoriteStudioMutation = { __typename: 'Mutation', favoriteStudio: boolean }; export type GenerateInviteCodesMutationVariables = Exact<{ input?: InputMaybe; }>; export type GenerateInviteCodesMutation = { __typename: 'Mutation', generateInviteCodes: Array }; export type GrantInviteMutationVariables = Exact<{ input: GrantInviteInput; }>; export type GrantInviteMutation = { __typename: 'Mutation', grantInvite: number }; export type MarkNotificationReadMutationVariables = Exact<{ notification: MarkNotificationReadInput; }>; export type MarkNotificationReadMutation = { __typename: 'Mutation', markNotificationsRead: boolean }; export type MarkNotificationsReadMutationVariables = Exact<{ [key: string]: never; }>; export type MarkNotificationsReadMutation = { __typename: 'Mutation', markNotificationsRead: boolean }; export type MoveFingerprintSubmissionsMutationVariables = Exact<{ input: MoveFingerprintSubmissionsInput; }>; export type MoveFingerprintSubmissionsMutation = { __typename: 'Mutation', sceneMoveFingerprintSubmissions: boolean }; export type NewUserMutationVariables = Exact<{ input: NewUserInput; }>; export type NewUserMutation = { __typename: 'Mutation', newUser?: string | null }; export type PerformerEditMutationVariables = Exact<{ performerData: PerformerEditInput; }>; export type PerformerEditMutation = { __typename: 'Mutation', performerEdit: { __typename: 'Edit', id: string, target_type: TargetTypeEnum, operation: OperationEnum, status: VoteStatusEnum, bot: boolean, applied: boolean, created: string, updated?: string | null, closed?: string | null, expires?: string | null, update_count: number, updatable: boolean, vote_count: number, destructive: boolean, comments: Array<{ __typename: 'EditComment', id: string, date: string, comment: string, user?: { __typename: 'User', id: string, name: string } | null }>, votes: Array<{ __typename: 'EditVote', date: string, vote: VoteTypeEnum, user?: { __typename: 'User', id: string, name: string } | null }>, user?: { __typename: 'User', id: string, name: string } | null, target?: | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, added_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, old_details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, merge_sources: Array< | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } >, options?: { __typename: 'PerformerEditOptions', set_modify_aliases: boolean, set_merge_aliases: boolean } | null } }; export type PerformerEditUpdateMutationVariables = Exact<{ id: Scalars['ID']['input']; performerData: PerformerEditInput; }>; export type PerformerEditUpdateMutation = { __typename: 'Mutation', performerEditUpdate: { __typename: 'Edit', id: string, target_type: TargetTypeEnum, operation: OperationEnum, status: VoteStatusEnum, bot: boolean, applied: boolean, created: string, updated?: string | null, closed?: string | null, expires?: string | null, update_count: number, updatable: boolean, vote_count: number, destructive: boolean, comments: Array<{ __typename: 'EditComment', id: string, date: string, comment: string, user?: { __typename: 'User', id: string, name: string } | null }>, votes: Array<{ __typename: 'EditVote', date: string, vote: VoteTypeEnum, user?: { __typename: 'User', id: string, name: string } | null }>, user?: { __typename: 'User', id: string, name: string } | null, target?: | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, added_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, old_details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, merge_sources: Array< | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } >, options?: { __typename: 'PerformerEditOptions', set_modify_aliases: boolean, set_merge_aliases: boolean } | null } }; export type RegenerateApiKeyMutationVariables = Exact<{ user_id?: InputMaybe; }>; export type RegenerateApiKeyMutation = { __typename: 'Mutation', regenerateAPIKey: string }; export type RequestChangeEmailMutationVariables = Exact<{ [key: string]: never; }>; export type RequestChangeEmailMutation = { __typename: 'Mutation', requestChangeEmail: UserChangeEmailStatus }; export type RescindInviteCodeMutationVariables = Exact<{ code: Scalars['ID']['input']; }>; export type RescindInviteCodeMutation = { __typename: 'Mutation', rescindInviteCode: boolean }; export type ResetPasswordMutationVariables = Exact<{ input: ResetPasswordInput; }>; export type ResetPasswordMutation = { __typename: 'Mutation', resetPassword: boolean }; export type RevokeInviteMutationVariables = Exact<{ input: RevokeInviteInput; }>; export type RevokeInviteMutation = { __typename: 'Mutation', revokeInvite: number }; export type SceneEditMutationVariables = Exact<{ sceneData: SceneEditInput; }>; export type SceneEditMutation = { __typename: 'Mutation', sceneEdit: { __typename: 'Edit', id: string, target_type: TargetTypeEnum, operation: OperationEnum, status: VoteStatusEnum, bot: boolean, applied: boolean, created: string, updated?: string | null, closed?: string | null, expires?: string | null, update_count: number, updatable: boolean, vote_count: number, destructive: boolean, comments: Array<{ __typename: 'EditComment', id: string, date: string, comment: string, user?: { __typename: 'User', id: string, name: string } | null }>, votes: Array<{ __typename: 'EditVote', date: string, vote: VoteTypeEnum, user?: { __typename: 'User', id: string, name: string } | null }>, user?: { __typename: 'User', id: string, name: string } | null, target?: | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, added_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, old_details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, merge_sources: Array< | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } >, options?: { __typename: 'PerformerEditOptions', set_modify_aliases: boolean, set_merge_aliases: boolean } | null } }; export type SceneEditUpdateMutationVariables = Exact<{ id: Scalars['ID']['input']; sceneData: SceneEditInput; }>; export type SceneEditUpdateMutation = { __typename: 'Mutation', sceneEditUpdate: { __typename: 'Edit', id: string, target_type: TargetTypeEnum, operation: OperationEnum, status: VoteStatusEnum, bot: boolean, applied: boolean, created: string, updated?: string | null, closed?: string | null, expires?: string | null, update_count: number, updatable: boolean, vote_count: number, destructive: boolean, comments: Array<{ __typename: 'EditComment', id: string, date: string, comment: string, user?: { __typename: 'User', id: string, name: string } | null }>, votes: Array<{ __typename: 'EditVote', date: string, vote: VoteTypeEnum, user?: { __typename: 'User', id: string, name: string } | null }>, user?: { __typename: 'User', id: string, name: string } | null, target?: | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, added_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, old_details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, merge_sources: Array< | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } >, options?: { __typename: 'PerformerEditOptions', set_modify_aliases: boolean, set_merge_aliases: boolean } | null } }; export type StudioEditMutationVariables = Exact<{ studioData: StudioEditInput; }>; export type StudioEditMutation = { __typename: 'Mutation', studioEdit: { __typename: 'Edit', id: string, target_type: TargetTypeEnum, operation: OperationEnum, status: VoteStatusEnum, bot: boolean, applied: boolean, created: string, updated?: string | null, closed?: string | null, expires?: string | null, update_count: number, updatable: boolean, vote_count: number, destructive: boolean, comments: Array<{ __typename: 'EditComment', id: string, date: string, comment: string, user?: { __typename: 'User', id: string, name: string } | null }>, votes: Array<{ __typename: 'EditVote', date: string, vote: VoteTypeEnum, user?: { __typename: 'User', id: string, name: string } | null }>, user?: { __typename: 'User', id: string, name: string } | null, target?: | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, added_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, old_details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, merge_sources: Array< | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } >, options?: { __typename: 'PerformerEditOptions', set_modify_aliases: boolean, set_merge_aliases: boolean } | null } }; export type StudioEditUpdateMutationVariables = Exact<{ id: Scalars['ID']['input']; studioData: StudioEditInput; }>; export type StudioEditUpdateMutation = { __typename: 'Mutation', studioEditUpdate: { __typename: 'Edit', id: string, target_type: TargetTypeEnum, operation: OperationEnum, status: VoteStatusEnum, bot: boolean, applied: boolean, created: string, updated?: string | null, closed?: string | null, expires?: string | null, update_count: number, updatable: boolean, vote_count: number, destructive: boolean, comments: Array<{ __typename: 'EditComment', id: string, date: string, comment: string, user?: { __typename: 'User', id: string, name: string } | null }>, votes: Array<{ __typename: 'EditVote', date: string, vote: VoteTypeEnum, user?: { __typename: 'User', id: string, name: string } | null }>, user?: { __typename: 'User', id: string, name: string } | null, target?: | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, added_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, old_details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, merge_sources: Array< | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } >, options?: { __typename: 'PerformerEditOptions', set_modify_aliases: boolean, set_merge_aliases: boolean } | null } }; export type TagEditMutationVariables = Exact<{ tagData: TagEditInput; }>; export type TagEditMutation = { __typename: 'Mutation', tagEdit: { __typename: 'Edit', id: string, target_type: TargetTypeEnum, operation: OperationEnum, status: VoteStatusEnum, bot: boolean, applied: boolean, created: string, updated?: string | null, closed?: string | null, expires?: string | null, update_count: number, updatable: boolean, vote_count: number, destructive: boolean, comments: Array<{ __typename: 'EditComment', id: string, date: string, comment: string, user?: { __typename: 'User', id: string, name: string } | null }>, votes: Array<{ __typename: 'EditVote', date: string, vote: VoteTypeEnum, user?: { __typename: 'User', id: string, name: string } | null }>, user?: { __typename: 'User', id: string, name: string } | null, target?: | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, added_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, old_details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, merge_sources: Array< | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } >, options?: { __typename: 'PerformerEditOptions', set_modify_aliases: boolean, set_merge_aliases: boolean } | null } }; export type TagEditUpdateMutationVariables = Exact<{ id: Scalars['ID']['input']; tagData: TagEditInput; }>; export type TagEditUpdateMutation = { __typename: 'Mutation', tagEditUpdate: { __typename: 'Edit', id: string, target_type: TargetTypeEnum, operation: OperationEnum, status: VoteStatusEnum, bot: boolean, applied: boolean, created: string, updated?: string | null, closed?: string | null, expires?: string | null, update_count: number, updatable: boolean, vote_count: number, destructive: boolean, comments: Array<{ __typename: 'EditComment', id: string, date: string, comment: string, user?: { __typename: 'User', id: string, name: string } | null }>, votes: Array<{ __typename: 'EditVote', date: string, vote: VoteTypeEnum, user?: { __typename: 'User', id: string, name: string } | null }>, user?: { __typename: 'User', id: string, name: string } | null, target?: | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, added_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, old_details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, merge_sources: Array< | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } >, options?: { __typename: 'PerformerEditOptions', set_modify_aliases: boolean, set_merge_aliases: boolean } | null } }; export type UnmatchFingerprintMutationVariables = Exact<{ scene_id: Scalars['ID']['input']; algorithm: FingerprintAlgorithm; hash: Scalars['FingerprintHash']['input']; duration: Scalars['Int']['input']; }>; export type UnmatchFingerprintMutation = { __typename: 'Mutation', unmatchFingerprint: boolean }; export type UpdateNotificationSubscriptionsMutationVariables = Exact<{ subscriptions: Array | NotificationEnum; }>; export type UpdateNotificationSubscriptionsMutation = { __typename: 'Mutation', updateNotificationSubscriptions: boolean }; export type UpdateSceneMutationVariables = Exact<{ updateData: SceneUpdateInput; }>; export type UpdateSceneMutation = { __typename: 'Mutation', sceneUpdate?: { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, title?: string | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string } }>, studio?: { __typename: 'Studio', id: string, name: string } | null, performers: Array<{ __typename: 'PerformerAppearance', performer: { __typename: 'Performer', name: string, id: string, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null }> } | null }; export type UpdateSiteMutationVariables = Exact<{ siteData: SiteUpdateInput; }>; export type UpdateSiteMutation = { __typename: 'Mutation', siteUpdate?: { __typename: 'Site', id: string, name: string, description?: string | null, url?: string | null, regex?: string | null, valid_types: Array } | null }; export type UpdateStudioMutationVariables = Exact<{ input: StudioUpdateInput; }>; export type UpdateStudioMutation = { __typename: 'Mutation', studioUpdate?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null }; export type UpdateTagCategoryMutationVariables = Exact<{ categoryData: TagCategoryUpdateInput; }>; export type UpdateTagCategoryMutation = { __typename: 'Mutation', tagCategoryUpdate?: { __typename: 'TagCategory', id: string, name: string, description?: string | null, group: TagGroupEnum } | null }; export type UpdateUserMutationVariables = Exact<{ userData: UserUpdateInput; }>; export type UpdateUserMutation = { __typename: 'Mutation', userUpdate?: { __typename: 'User', id: string, name: string, email?: string | null, roles?: Array | null } | null }; export type ValidateChangeEmailMutationVariables = Exact<{ token: Scalars['ID']['input']; email: Scalars['String']['input']; }>; export type ValidateChangeEmailMutation = { __typename: 'Mutation', validateChangeEmail: UserChangeEmailStatus }; export type VoteMutationVariables = Exact<{ input: EditVoteInput; }>; export type VoteMutation = { __typename: 'Mutation', editVote: { __typename: 'Edit', id: string, target_type: TargetTypeEnum, operation: OperationEnum, status: VoteStatusEnum, bot: boolean, applied: boolean, created: string, updated?: string | null, closed?: string | null, expires?: string | null, update_count: number, updatable: boolean, vote_count: number, destructive: boolean, comments: Array<{ __typename: 'EditComment', id: string, date: string, comment: string, user?: { __typename: 'User', id: string, name: string } | null }>, votes: Array<{ __typename: 'EditVote', date: string, vote: VoteTypeEnum, user?: { __typename: 'User', id: string, name: string } | null }>, user?: { __typename: 'User', id: string, name: string } | null, target?: | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, added_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, old_details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, merge_sources: Array< | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } >, options?: { __typename: 'PerformerEditOptions', set_modify_aliases: boolean, set_merge_aliases: boolean } | null } }; export type CategoriesQueryVariables = Exact<{ [key: string]: never; }>; export type CategoriesQuery = { __typename: 'Query', queryTagCategories: { __typename: 'QueryTagCategoriesResultType', count: number, tag_categories: Array<{ __typename: 'TagCategory', id: string, name: string, description?: string | null, group: TagGroupEnum }> } }; export type CategoryQueryVariables = Exact<{ id: Scalars['ID']['input']; }>; export type CategoryQuery = { __typename: 'Query', findTagCategory?: { __typename: 'TagCategory', id: string, name: string, description?: string | null, group: TagGroupEnum } | null }; export type ConfigQueryVariables = Exact<{ [key: string]: never; }>; export type ConfigQuery = { __typename: 'Query', getConfig: { __typename: 'StashBoxConfig', edit_update_limit: number, host_url: string, require_invite: boolean, require_activation: boolean, vote_promotion_threshold?: number | null, vote_application_threshold: number, voting_period: number, min_destructive_voting_period: number, vote_cron_interval: string, guidelines_url: string, require_scene_draft: boolean, require_tag_role: boolean } }; export type DraftQueryVariables = Exact<{ id: Scalars['ID']['input']; }>; export type DraftQuery = { __typename: 'Query', findDraft?: { __typename: 'Draft', id: string, created: string, expires: string, data: | { __typename: 'PerformerDraft', id?: string | null, name: string, disambiguation?: string | null, aliases?: string | null, gender?: string | null, birthdate?: string | null, deathdate?: string | null, urls?: Array | null, ethnicity?: string | null, country?: string | null, eye_color?: string | null, hair_color?: string | null, height?: string | null, measurements?: string | null, breast_type?: string | null, tattoos?: string | null, piercings?: string | null, career_start_year?: number | null, career_end_year?: number | null, image?: { __typename: 'Image', id: string, url: string, width: number, height: number } | null } | { __typename: 'SceneDraft', id?: string | null, title?: string | null, code?: string | null, details?: string | null, director?: string | null, date?: string | null, urls?: Array | null, studio?: | { __typename: 'DraftEntity', name: string, draftID?: string | null } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, performers: Array< | { __typename: 'DraftEntity', name: string, draftID?: string | null } | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } >, tags?: Array< | { __typename: 'DraftEntity', name: string, draftID?: string | null } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } > | null, fingerprints: Array<{ __typename: 'DraftFingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }>, image?: { __typename: 'Image', id: string, url: string, width: number, height: number } | null } } | null }; export type DraftsQueryVariables = Exact<{ [key: string]: never; }>; export type DraftsQuery = { __typename: 'Query', findDrafts: Array<{ __typename: 'Draft', id: string, created: string, expires: string, data: | { __typename: 'PerformerDraft', id?: string | null, name: string } | { __typename: 'SceneDraft', id?: string | null, title?: string | null } }> }; export type EditQueryVariables = Exact<{ id: Scalars['ID']['input']; }>; export type EditQuery = { __typename: 'Query', findEdit?: { __typename: 'Edit', id: string, target_type: TargetTypeEnum, operation: OperationEnum, status: VoteStatusEnum, bot: boolean, applied: boolean, created: string, updated?: string | null, closed?: string | null, expires?: string | null, update_count: number, updatable: boolean, vote_count: number, destructive: boolean, comments: Array<{ __typename: 'EditComment', id: string, date: string, comment: string, user?: { __typename: 'User', id: string, name: string } | null }>, votes: Array<{ __typename: 'EditVote', date: string, vote: VoteTypeEnum, user?: { __typename: 'User', id: string, name: string } | null }>, user?: { __typename: 'User', id: string, name: string } | null, target?: | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, added_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, old_details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, merge_sources: Array< | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } >, options?: { __typename: 'PerformerEditOptions', set_modify_aliases: boolean, set_merge_aliases: boolean } | null } | null }; export type EditUpdateQueryVariables = Exact<{ id: Scalars['ID']['input']; }>; export type EditUpdateQuery = { __typename: 'Query', findEdit?: { __typename: 'Edit', id: string, target_type: TargetTypeEnum, operation: OperationEnum, status: VoteStatusEnum, applied: boolean, closed?: string | null, created: string, updated?: string | null, updatable: boolean, update_count: number, vote_count: number, merge_sources: Array< | { __typename: 'Performer', id: string } | { __typename: 'Scene', id: string } | { __typename: 'Studio', id: string } | { __typename: 'Tag', id: string } >, options?: { __typename: 'PerformerEditOptions', set_modify_aliases: boolean, set_merge_aliases: boolean } | null, user?: { __typename: 'User', id: string, name: string } | null, target?: | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', aliases: Array, id: string, name: string, description?: string | null, deleted: boolean, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null, aliases: Array, draft_id?: string | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, tattoos: Array<{ __typename: 'BodyModification', location: string, description?: string | null }>, piercings: Array<{ __typename: 'BodyModification', location: string, description?: string | null }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, draft_id?: string | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> } | { __typename: 'StudioEdit', name?: string | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'TagEdit', name?: string | null, description?: string | null, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null } | null }; export type EditsQueryVariables = Exact<{ input: EditQueryInput; }>; export type EditsQuery = { __typename: 'Query', queryEdits: { __typename: 'QueryEditsResultType', count: number, edits: Array<{ __typename: 'Edit', id: string, target_type: TargetTypeEnum, operation: OperationEnum, status: VoteStatusEnum, bot: boolean, applied: boolean, created: string, updated?: string | null, closed?: string | null, expires?: string | null, update_count: number, updatable: boolean, vote_count: number, destructive: boolean, comments: Array<{ __typename: 'EditComment', id: string, date: string, comment: string, user?: { __typename: 'User', id: string, name: string } | null }>, votes: Array<{ __typename: 'EditVote', date: string, vote: VoteTypeEnum, user?: { __typename: 'User', id: string, name: string } | null }>, user?: { __typename: 'User', id: string, name: string } | null, target?: | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, added_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, old_details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, merge_sources: Array< | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } >, options?: { __typename: 'PerformerEditOptions', set_modify_aliases: boolean, set_merge_aliases: boolean } | null }> } }; export type FullPerformerQueryVariables = Exact<{ id: Scalars['ID']['input']; }>; export type FullPerformerQuery = { __typename: 'Query', findPerformer?: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, studios: Array<{ __typename: 'PerformerStudio', scene_count: number, studio: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } }>, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | null }; export type MeQueryVariables = Exact<{ [key: string]: never; }>; export type MeQuery = { __typename: 'Query', me?: { __typename: 'User', id: string, name: string, roles?: Array | null } | null }; export type ModAuditsQueryVariables = Exact<{ input: ModAuditQueryInput; }>; export type ModAuditsQuery = { __typename: 'Query', queryModAudits: { __typename: 'QueryModAuditsResultType', count: number, audits: Array<{ __typename: 'ModAudit', id: string, action: ModAuditActionEnum, target_id: string, target_type: string, data: string, reason?: string | null, created_at: string, user?: { __typename: 'User', id: string, name: string } | null }> } }; export type PendingEditsCountQueryVariables = Exact<{ type: TargetTypeEnum; id: Scalars['ID']['input']; }>; export type PendingEditsCountQuery = { __typename: 'Query', queryEdits: { __typename: 'QueryEditsResultType', count: number } }; export type PerformerQueryVariables = Exact<{ id: Scalars['ID']['input']; }>; export type PerformerQuery = { __typename: 'Query', findPerformer?: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | null }; export type PerformersQueryVariables = Exact<{ input: PerformerQueryInput; }>; export type PerformersQuery = { __typename: 'Query', queryPerformers: { __typename: 'QueryPerformersResultType', count: number, performers: Array<{ __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> }> } }; export type PublicUserQueryVariables = Exact<{ name: Scalars['String']['input']; }>; export type PublicUserQuery = { __typename: 'Query', findUser?: { __typename: 'User', id: string, name: string, vote_count: { __typename: 'UserVoteCount', accept: number, reject: number, immediate_accept: number, immediate_reject: number, abstain: number }, edit_count: { __typename: 'UserEditCount', immediate_accepted: number, immediate_rejected: number, accepted: number, rejected: number, failed: number, canceled: number, pending: number } } | null }; export type QueryExistingPerformerQueryVariables = Exact<{ input: QueryExistingPerformerInput; }>; export type QueryExistingPerformerQuery = { __typename: 'Query', queryExistingPerformer: { __typename: 'QueryExistingPerformerResult', performers: Array<{ __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> }>, edits: Array<{ __typename: 'Edit', id: string, target_type: TargetTypeEnum, operation: OperationEnum, status: VoteStatusEnum, bot: boolean, applied: boolean, created: string, updated?: string | null, closed?: string | null, expires?: string | null, update_count: number, updatable: boolean, vote_count: number, destructive: boolean, comments: Array<{ __typename: 'EditComment', id: string, date: string, comment: string, user?: { __typename: 'User', id: string, name: string } | null }>, votes: Array<{ __typename: 'EditVote', date: string, vote: VoteTypeEnum, user?: { __typename: 'User', id: string, name: string } | null }>, user?: { __typename: 'User', id: string, name: string } | null, target?: | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, added_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, old_details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, merge_sources: Array< | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } >, options?: { __typename: 'PerformerEditOptions', set_modify_aliases: boolean, set_merge_aliases: boolean } | null }> } }; export type QueryExistingSceneQueryVariables = Exact<{ input: QueryExistingSceneInput; }>; export type QueryExistingSceneQuery = { __typename: 'Query', queryExistingScene: { __typename: 'QueryExistingSceneResult', scenes: Array<{ __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> }>, edits: Array<{ __typename: 'Edit', id: string, target_type: TargetTypeEnum, operation: OperationEnum, status: VoteStatusEnum, bot: boolean, applied: boolean, created: string, updated?: string | null, closed?: string | null, expires?: string | null, update_count: number, updatable: boolean, vote_count: number, destructive: boolean, comments: Array<{ __typename: 'EditComment', id: string, date: string, comment: string, user?: { __typename: 'User', id: string, name: string } | null }>, votes: Array<{ __typename: 'EditVote', date: string, vote: VoteTypeEnum, user?: { __typename: 'User', id: string, name: string } | null }>, user?: { __typename: 'User', id: string, name: string } | null, target?: | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, added_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, old_details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, merge_sources: Array< | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } >, options?: { __typename: 'PerformerEditOptions', set_modify_aliases: boolean, set_merge_aliases: boolean } | null }> } }; export type NotificationCommentFragment = { __typename: 'EditComment', id: string, date: string, comment: string, edit: { __typename: 'Edit', id: string, target_type: TargetTypeEnum, operation: OperationEnum, status: VoteStatusEnum, bot: boolean, applied: boolean, created: string, updated?: string | null, closed?: string | null, expires?: string | null, update_count: number, updatable: boolean, vote_count: number, destructive: boolean, comments: Array<{ __typename: 'EditComment', id: string, date: string, comment: string, user?: { __typename: 'User', id: string, name: string } | null }>, votes: Array<{ __typename: 'EditVote', date: string, vote: VoteTypeEnum, user?: { __typename: 'User', id: string, name: string } | null }>, user?: { __typename: 'User', id: string, name: string } | null, target?: | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, added_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, old_details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, merge_sources: Array< | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } >, options?: { __typename: 'PerformerEditOptions', set_modify_aliases: boolean, set_merge_aliases: boolean } | null }, user?: { __typename: 'User', id: string, name: string } | null }; export type NotificationsQueryVariables = Exact<{ input: QueryNotificationsInput; }>; export type NotificationsQuery = { __typename: 'Query', queryNotifications: { __typename: 'QueryNotificationsResult', count: number, notifications: Array<{ __typename: 'Notification', created: string, read: boolean, data: | { __typename: 'CommentCommentedEdit', comment: { __typename: 'EditComment', id: string, date: string, comment: string, edit: { __typename: 'Edit', id: string, target_type: TargetTypeEnum, operation: OperationEnum, status: VoteStatusEnum, bot: boolean, applied: boolean, created: string, updated?: string | null, closed?: string | null, expires?: string | null, update_count: number, updatable: boolean, vote_count: number, destructive: boolean, comments: Array<{ __typename: 'EditComment', id: string, date: string, comment: string, user?: { __typename: 'User', id: string, name: string } | null }>, votes: Array<{ __typename: 'EditVote', date: string, vote: VoteTypeEnum, user?: { __typename: 'User', id: string, name: string } | null }>, user?: { __typename: 'User', id: string, name: string } | null, target?: | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, added_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, old_details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, merge_sources: Array< | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } >, options?: { __typename: 'PerformerEditOptions', set_modify_aliases: boolean, set_merge_aliases: boolean } | null }, user?: { __typename: 'User', id: string, name: string } | null } } | { __typename: 'CommentOwnEdit', comment: { __typename: 'EditComment', id: string, date: string, comment: string, edit: { __typename: 'Edit', id: string, target_type: TargetTypeEnum, operation: OperationEnum, status: VoteStatusEnum, bot: boolean, applied: boolean, created: string, updated?: string | null, closed?: string | null, expires?: string | null, update_count: number, updatable: boolean, vote_count: number, destructive: boolean, comments: Array<{ __typename: 'EditComment', id: string, date: string, comment: string, user?: { __typename: 'User', id: string, name: string } | null }>, votes: Array<{ __typename: 'EditVote', date: string, vote: VoteTypeEnum, user?: { __typename: 'User', id: string, name: string } | null }>, user?: { __typename: 'User', id: string, name: string } | null, target?: | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, added_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, old_details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, merge_sources: Array< | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } >, options?: { __typename: 'PerformerEditOptions', set_modify_aliases: boolean, set_merge_aliases: boolean } | null }, user?: { __typename: 'User', id: string, name: string } | null } } | { __typename: 'CommentVotedEdit', comment: { __typename: 'EditComment', id: string, date: string, comment: string, edit: { __typename: 'Edit', id: string, target_type: TargetTypeEnum, operation: OperationEnum, status: VoteStatusEnum, bot: boolean, applied: boolean, created: string, updated?: string | null, closed?: string | null, expires?: string | null, update_count: number, updatable: boolean, vote_count: number, destructive: boolean, comments: Array<{ __typename: 'EditComment', id: string, date: string, comment: string, user?: { __typename: 'User', id: string, name: string } | null }>, votes: Array<{ __typename: 'EditVote', date: string, vote: VoteTypeEnum, user?: { __typename: 'User', id: string, name: string } | null }>, user?: { __typename: 'User', id: string, name: string } | null, target?: | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, added_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, old_details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, merge_sources: Array< | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } >, options?: { __typename: 'PerformerEditOptions', set_modify_aliases: boolean, set_merge_aliases: boolean } | null }, user?: { __typename: 'User', id: string, name: string } | null } } | { __typename: 'DownvoteOwnEdit', edit: { __typename: 'Edit', id: string, target_type: TargetTypeEnum, operation: OperationEnum, status: VoteStatusEnum, bot: boolean, applied: boolean, created: string, updated?: string | null, closed?: string | null, expires?: string | null, update_count: number, updatable: boolean, vote_count: number, destructive: boolean, comments: Array<{ __typename: 'EditComment', id: string, date: string, comment: string, user?: { __typename: 'User', id: string, name: string } | null }>, votes: Array<{ __typename: 'EditVote', date: string, vote: VoteTypeEnum, user?: { __typename: 'User', id: string, name: string } | null }>, user?: { __typename: 'User', id: string, name: string } | null, target?: | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, added_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, old_details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, merge_sources: Array< | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } >, options?: { __typename: 'PerformerEditOptions', set_modify_aliases: boolean, set_merge_aliases: boolean } | null } } | { __typename: 'FailedOwnEdit', edit: { __typename: 'Edit', id: string, target_type: TargetTypeEnum, operation: OperationEnum, status: VoteStatusEnum, bot: boolean, applied: boolean, created: string, updated?: string | null, closed?: string | null, expires?: string | null, update_count: number, updatable: boolean, vote_count: number, destructive: boolean, comments: Array<{ __typename: 'EditComment', id: string, date: string, comment: string, user?: { __typename: 'User', id: string, name: string } | null }>, votes: Array<{ __typename: 'EditVote', date: string, vote: VoteTypeEnum, user?: { __typename: 'User', id: string, name: string } | null }>, user?: { __typename: 'User', id: string, name: string } | null, target?: | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, added_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, old_details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, merge_sources: Array< | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } >, options?: { __typename: 'PerformerEditOptions', set_modify_aliases: boolean, set_merge_aliases: boolean } | null } } | { __typename: 'FavoritePerformerEdit', edit: { __typename: 'Edit', id: string, target_type: TargetTypeEnum, operation: OperationEnum, status: VoteStatusEnum, bot: boolean, applied: boolean, created: string, updated?: string | null, closed?: string | null, expires?: string | null, update_count: number, updatable: boolean, vote_count: number, destructive: boolean, comments: Array<{ __typename: 'EditComment', id: string, date: string, comment: string, user?: { __typename: 'User', id: string, name: string } | null }>, votes: Array<{ __typename: 'EditVote', date: string, vote: VoteTypeEnum, user?: { __typename: 'User', id: string, name: string } | null }>, user?: { __typename: 'User', id: string, name: string } | null, target?: | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, added_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, old_details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, merge_sources: Array< | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } >, options?: { __typename: 'PerformerEditOptions', set_modify_aliases: boolean, set_merge_aliases: boolean } | null } } | { __typename: 'FavoritePerformerScene', scene: { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } } | { __typename: 'FavoriteStudioEdit', edit: { __typename: 'Edit', id: string, target_type: TargetTypeEnum, operation: OperationEnum, status: VoteStatusEnum, bot: boolean, applied: boolean, created: string, updated?: string | null, closed?: string | null, expires?: string | null, update_count: number, updatable: boolean, vote_count: number, destructive: boolean, comments: Array<{ __typename: 'EditComment', id: string, date: string, comment: string, user?: { __typename: 'User', id: string, name: string } | null }>, votes: Array<{ __typename: 'EditVote', date: string, vote: VoteTypeEnum, user?: { __typename: 'User', id: string, name: string } | null }>, user?: { __typename: 'User', id: string, name: string } | null, target?: | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, added_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, old_details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, merge_sources: Array< | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } >, options?: { __typename: 'PerformerEditOptions', set_modify_aliases: boolean, set_merge_aliases: boolean } | null } } | { __typename: 'FavoriteStudioScene', scene: { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } } | { __typename: 'FingerprintedSceneEdit', edit: { __typename: 'Edit', id: string, target_type: TargetTypeEnum, operation: OperationEnum, status: VoteStatusEnum, bot: boolean, applied: boolean, created: string, updated?: string | null, closed?: string | null, expires?: string | null, update_count: number, updatable: boolean, vote_count: number, destructive: boolean, comments: Array<{ __typename: 'EditComment', id: string, date: string, comment: string, user?: { __typename: 'User', id: string, name: string } | null }>, votes: Array<{ __typename: 'EditVote', date: string, vote: VoteTypeEnum, user?: { __typename: 'User', id: string, name: string } | null }>, user?: { __typename: 'User', id: string, name: string } | null, target?: | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, added_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, old_details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, merge_sources: Array< | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } >, options?: { __typename: 'PerformerEditOptions', set_modify_aliases: boolean, set_merge_aliases: boolean } | null } } | { __typename: 'UpdatedEdit', edit: { __typename: 'Edit', id: string, target_type: TargetTypeEnum, operation: OperationEnum, status: VoteStatusEnum, bot: boolean, applied: boolean, created: string, updated?: string | null, closed?: string | null, expires?: string | null, update_count: number, updatable: boolean, vote_count: number, destructive: boolean, comments: Array<{ __typename: 'EditComment', id: string, date: string, comment: string, user?: { __typename: 'User', id: string, name: string } | null }>, votes: Array<{ __typename: 'EditVote', date: string, vote: VoteTypeEnum, user?: { __typename: 'User', id: string, name: string } | null }>, user?: { __typename: 'User', id: string, name: string } | null, target?: | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, added_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, removed_piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, draft_id?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, added_aliases?: Array | null, removed_aliases?: Array | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, old_details?: | { __typename: 'PerformerEdit', name?: string | null, disambiguation?: string | null, gender?: GenderEnum | null, birthdate?: string | null, deathdate?: string | null, ethnicity?: EthnicityEnum | null, country?: string | null, eye_color?: EyeColorEnum | null, hair_color?: HairColorEnum | null, height?: number | null, cup_size?: string | null, band_size?: number | null, waist_size?: number | null, hip_size?: number | null, breast_type?: BreastTypeEnum | null, career_start_year?: number | null, career_end_year?: number | null } | { __typename: 'SceneEdit', title?: string | null, details?: string | null, date?: string | null, production_date?: string | null, duration?: number | null, director?: string | null, code?: string | null, added_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, removed_urls?: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }> | null, studio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null, added_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, removed_performers?: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } }> | null, added_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, removed_tags?: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null }> | null, added_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, removed_images?: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> | null, added_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null, removed_fingerprints?: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number }> | null } | { __typename: 'StudioEdit', name?: string | null, parent?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null } | { __typename: 'TagEdit', name?: string | null, description?: string | null, category?: { __typename: 'TagCategory', id: string, name: string } | null } | null, merge_sources: Array< | { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, merged_into_id?: string | null, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, death_date?: string | null, age?: number | null, height?: number | null, hair_color?: HairColorEnum | null, eye_color?: EyeColorEnum | null, ethnicity?: EthnicityEnum | null, country?: string | null, career_end_year?: number | null, career_start_year?: number | null, breast_type?: BreastTypeEnum | null, waist_size?: number | null, hip_size?: number | null, band_size?: number | null, cup_size?: string | null, is_favorite: boolean, tattoos?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, piercings?: Array<{ __typename: 'BodyModification', location: string, description?: string | null }> | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> } | { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | { __typename: 'Tag', id: string, name: string, description?: string | null, deleted: boolean, aliases: Array, category?: { __typename: 'TagCategory', id: string, name: string } | null } >, options?: { __typename: 'PerformerEditOptions', set_modify_aliases: boolean, set_merge_aliases: boolean } | null } } }> } }; export type SceneQueryVariables = Exact<{ id: Scalars['ID']['input']; }>; export type SceneQuery = { __typename: 'Query', findScene?: { __typename: 'Scene', id: string, release_date?: string | null, production_date?: string | null, title?: string | null, deleted: boolean, details?: string | null, director?: string | null, code?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string, parent?: { __typename: 'Studio', id: string, name: string } | null } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }>, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, reports: number, user_submitted: boolean, user_reported: boolean, created: string, updated: string }>, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } | null }; export type ScenePairingsQueryVariables = Exact<{ performerId: Scalars['ID']['input']; names?: InputMaybe; gender?: InputMaybe; favorite?: InputMaybe; page?: Scalars['Int']['input']; per_page?: Scalars['Int']['input']; direction: SortDirectionEnum; sort: PerformerSortEnum; fetchScenes: Scalars['Boolean']['input']; }>; export type ScenePairingsQuery = { __typename: 'Query', queryPerformers: { __typename: 'QueryPerformersResultType', count: number, performers: Array<{ __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, is_favorite: boolean, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, scenes?: Array<{ __typename: 'Scene', id: string, title?: string | null, date?: string | null, duration?: number | null, release_date?: string | null, studio?: { __typename: 'Studio', id: string, name: string } | null, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> }> }> } }; export type ScenesQueryVariables = Exact<{ input: SceneQueryInput; }>; export type ScenesQuery = { __typename: 'Query', queryScenes: { __typename: 'QueryScenesResultType', count: number, scenes: Array<{ __typename: 'Scene', id: string, release_date?: string | null, title?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }> }> } }; export type ScenesWithFingerprintsQueryVariables = Exact<{ input: SceneQueryInput; submitted: Scalars['Boolean']['input']; }>; export type ScenesWithFingerprintsQuery = { __typename: 'Query', queryScenes: { __typename: 'QueryScenesResultType', count: number, scenes: Array<{ __typename: 'Scene', id: string, release_date?: string | null, title?: string | null, duration?: number | null, fingerprints: Array<{ __typename: 'Fingerprint', hash: string, algorithm: FingerprintAlgorithm, duration: number, submissions: number, user_submitted: boolean, created: string, updated: string }>, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }> }> } }; export type ScenesWithoutCountQueryVariables = Exact<{ input: SceneQueryInput; }>; export type ScenesWithoutCountQuery = { __typename: 'Query', queryScenes: { __typename: 'QueryScenesResultType', scenes: Array<{ __typename: 'Scene', id: string, release_date?: string | null, title?: string | null, duration?: number | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array } }> }> } }; export type SearchAllQueryVariables = Exact<{ term: Scalars['String']['input']; limit?: InputMaybe; }>; export type SearchAllQuery = { __typename: 'Query', searchPerformers: { __typename: 'QueryPerformersResultType', count: number, performers: Array<{ __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array, country?: string | null, career_start_year?: number | null, career_end_year?: number | null, scene_count: number, birth_date?: string | null, is_favorite: boolean, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> }> }, searchScenes: { __typename: 'QueryScenesResultType', count: number, scenes: Array<{ __typename: 'Scene', id: string, release_date?: string | null, title?: string | null, deleted: boolean, duration?: number | null, code?: string | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, gender?: GenderEnum | null, aliases: Array, deleted: boolean } }> }> } }; export type SearchPerformersQueryVariables = Exact<{ term: Scalars['String']['input']; page?: InputMaybe; per_page?: InputMaybe; filter?: InputMaybe; studioId?: InputMaybe; hasStudioId?: Scalars['Boolean']['input']; }>; export type SearchPerformersQuery = { __typename: 'Query', searchPerformers: { __typename: 'QueryPerformersResultType', count: number, performers: Array<{ __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, gender?: GenderEnum | null, aliases: Array, country?: string | null, career_start_year?: number | null, career_end_year?: number | null, scene_count: number, birth_date?: string | null, is_favorite: boolean, studios?: Array<{ __typename: 'PerformerStudio', scene_count: number }>, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> }>, facets?: { __typename: 'PerformerSearchFacets', genders: Array<{ __typename: 'GenderFacet', gender: GenderEnum, count: number }> } | null } }; export type SearchScenesQueryVariables = Exact<{ term: Scalars['String']['input']; page?: InputMaybe; per_page?: InputMaybe; }>; export type SearchScenesQuery = { __typename: 'Query', searchScenes: { __typename: 'QueryScenesResultType', count: number, scenes: Array<{ __typename: 'Scene', id: string, release_date?: string | null, title?: string | null, deleted: boolean, duration?: number | null, code?: string | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, studio?: { __typename: 'Studio', id: string, name: string } | null, performers: Array<{ __typename: 'PerformerAppearance', as?: string | null, performer: { __typename: 'Performer', id: string, name: string, disambiguation?: string | null, gender?: GenderEnum | null, aliases: Array, deleted: boolean } }> }> } }; export type SearchTagFragment = { __typename: 'Tag', deleted: boolean, id: string, name: string, description?: string | null, aliases: Array }; export type SearchTagsQueryVariables = Exact<{ term: Scalars['String']['input']; limit?: InputMaybe; }>; export type SearchTagsQuery = { __typename: 'Query', exact?: { __typename: 'Tag', deleted: boolean, id: string, name: string, description?: string | null, aliases: Array } | null, query: Array<{ __typename: 'Tag', deleted: boolean, id: string, name: string, description?: string | null, aliases: Array }> }; export type SiteQueryVariables = Exact<{ id: Scalars['ID']['input']; }>; export type SiteQuery = { __typename: 'Query', findSite?: { __typename: 'Site', id: string, name: string, description?: string | null, url?: string | null, regex?: string | null, valid_types: Array, icon: string, created: string, updated: string } | null }; export type SitesQueryVariables = Exact<{ [key: string]: never; }>; export type SitesQuery = { __typename: 'Query', querySites: { __typename: 'QuerySitesResultType', sites: Array<{ __typename: 'Site', id: string, name: string, description?: string | null, url?: string | null, regex?: string | null, valid_types: Array, icon: string, created: string, updated: string }> } }; export type StudioQueryVariables = Exact<{ id: Scalars['ID']['input']; }>; export type StudioQuery = { __typename: 'Query', findStudio?: { __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, sub_studios: { __typename: 'QueryStudiosResultType', count: number }, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, height: number, width: number }> } | null }; export type StudioPerformersQueryVariables = Exact<{ studioId: Scalars['ID']['input']; gender?: InputMaybe; favorite?: InputMaybe; names?: InputMaybe; page?: Scalars['Int']['input']; per_page?: Scalars['Int']['input']; direction: SortDirectionEnum; sort: PerformerSortEnum; }>; export type StudioPerformersQuery = { __typename: 'Query', queryPerformers: { __typename: 'QueryPerformersResultType', count: number, performers: Array<{ __typename: 'Performer', id: string, name: string, disambiguation?: string | null, deleted: boolean, aliases: Array, gender?: GenderEnum | null, birth_date?: string | null, is_favorite: boolean, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }>, scenes: Array<{ __typename: 'Scene', id: string, title?: string | null, duration?: number | null, release_date?: string | null, production_date?: string | null, studio?: { __typename: 'Studio', id: string, name: string } | null, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> }> }> } }; export type StudiosQueryVariables = Exact<{ input: StudioQueryInput; }>; export type StudiosQuery = { __typename: 'Query', queryStudios: { __typename: 'QueryStudiosResultType', count: number, studios: Array<{ __typename: 'Studio', id: string, name: string, aliases: Array, deleted: boolean, is_favorite: boolean, parent?: { __typename: 'Studio', id: string, name: string } | null, urls: Array<{ __typename: 'URL', url: string, site: { __typename: 'Site', id: string, name: string, icon: string } }>, images: Array<{ __typename: 'Image', id: string, url: string, width: number, height: number }> }> } }; export type SubStudiosQueryVariables = Exact<{ id: Scalars['ID']['input']; input: StudioQueryInput; }>; export type SubStudiosQuery = { __typename: 'Query', findStudio?: { __typename: 'Studio', sub_studios: { __typename: 'QueryStudiosResultType', count: number, studios: Array<{ __typename: 'Studio', id: string, name: string }> } } | null }; export type TagQueryVariables = Exact<{ name?: InputMaybe; id?: InputMaybe; }>; export type TagQuery = { __typename: 'Query', findTag?: { __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array, deleted: boolean, category?: { __typename: 'TagCategory', id: string, name: string, group: TagGroupEnum, description?: string | null } | null } | null }; export type TagsQueryVariables = Exact<{ input: TagQueryInput; }>; export type TagsQuery = { __typename: 'Query', queryTags: { __typename: 'QueryTagsResultType', count: number, tags: Array<{ __typename: 'Tag', id: string, name: string, description?: string | null, aliases: Array }> } }; export type UnreadNotificationCountQueryVariables = Exact<{ [key: string]: never; }>; export type UnreadNotificationCountQuery = { __typename: 'Query', getUnreadNotificationCount: number }; export type UserQueryVariables = Exact<{ name: Scalars['String']['input']; }>; export type UserQuery = { __typename: 'Query', findUser?: { __typename: 'User', id: string, name: string, email?: string | null, roles?: Array | null, api_key?: string | null, api_calls: number, invite_tokens?: number | null, notification_subscriptions: Array, invited_by?: { __typename: 'User', id: string, name: string } | null, invite_codes?: Array<{ __typename: 'InviteKey', id: string, uses?: number | null, expires?: string | null }> | null, vote_count: { __typename: 'UserVoteCount', accept: number, reject: number, immediate_accept: number, immediate_reject: number, abstain: number }, edit_count: { __typename: 'UserEditCount', immediate_accepted: number, immediate_rejected: number, accepted: number, rejected: number, failed: number, canceled: number, pending: number } } | null }; export type UsersQueryVariables = Exact<{ input: UserQueryInput; }>; export type UsersQuery = { __typename: 'Query', queryUsers: { __typename: 'QueryUsersResultType', count: number, users: Array<{ __typename: 'User', id: string, name: string, email?: string | null, roles?: Array | null, api_key?: string | null, api_calls: number, invite_tokens?: number | null, invited_by?: { __typename: 'User', id: string, name: string } | null }> } }; export type VersionQueryVariables = Exact<{ [key: string]: never; }>; export type VersionQuery = { __typename: 'Query', version: { __typename: 'Version', hash: string, version: string, build_time: string, build_type: string } }; export const UrlFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}}]} as unknown as DocumentNode; export const ImageFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}}]} as unknown as DocumentNode; export const ScenePerformerFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ScenePerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}}]} as unknown as DocumentNode; export const QuerySceneFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"QuerySceneFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"release_date"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"as"}},{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ScenePerformerFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ScenePerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}}]} as unknown as DocumentNode; export const SearchPerformerFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SearchPerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"scene_count"}},{"kind":"Field","name":{"kind":"Name","value":"birth_date"}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}}]} as unknown as DocumentNode; export const CommentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CommentFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EditComment"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"comment"}}]}}]} as unknown as DocumentNode; export const TagFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TagFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}}]} as unknown as DocumentNode; export const PerformerFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"merged_into_id"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birth_date"}},{"kind":"Field","name":{"kind":"Name","value":"death_date"}},{"kind":"Field","name":{"kind":"Name","value":"age"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}}]} as unknown as DocumentNode; export const StudioFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"StudioFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}}]}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}}]} as unknown as DocumentNode; export const SceneFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SceneFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"release_date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"as"}},{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ScenePerformerFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"submissions"}},{"kind":"Field","name":{"kind":"Name","value":"reports"}},{"kind":"Field","name":{"kind":"Name","value":"user_submitted"}},{"kind":"Field","name":{"kind":"Name","value":"user_reported"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ScenePerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}}]} as unknown as DocumentNode; export const FingerprintFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FingerprintFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Fingerprint"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}}]}}]} as unknown as DocumentNode; export const EditFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EditFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Edit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"target_type"}},{"kind":"Field","name":{"kind":"Name","value":"operation"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"bot"}},{"kind":"Field","name":{"kind":"Name","value":"applied"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}},{"kind":"Field","name":{"kind":"Name","value":"closed"}},{"kind":"Field","name":{"kind":"Name","value":"expires"}},{"kind":"Field","name":{"kind":"Name","value":"update_count"}},{"kind":"Field","name":{"kind":"Name","value":"updatable"}},{"kind":"Field","name":{"kind":"Name","value":"vote_count"}},{"kind":"Field","name":{"kind":"Name","value":"destructive"}},{"kind":"Field","name":{"kind":"Name","value":"comments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CommentFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"votes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"vote"}}]}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"target"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"added_tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"old_details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"merge_sources"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"options"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"set_modify_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"set_merge_aliases"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ScenePerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CommentFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EditComment"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"comment"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TagFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"merged_into_id"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birth_date"}},{"kind":"Field","name":{"kind":"Name","value":"death_date"}},{"kind":"Field","name":{"kind":"Name","value":"age"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"StudioFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}}]}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SceneFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"release_date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"as"}},{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ScenePerformerFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"submissions"}},{"kind":"Field","name":{"kind":"Name","value":"reports"}},{"kind":"Field","name":{"kind":"Name","value":"user_submitted"}},{"kind":"Field","name":{"kind":"Name","value":"user_reported"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FingerprintFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Fingerprint"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}}]}}]} as unknown as DocumentNode; export const NotificationCommentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationCommentFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EditComment"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CommentFragment"}},{"kind":"Field","name":{"kind":"Name","value":"edit"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EditFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CommentFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EditComment"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"comment"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TagFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"merged_into_id"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birth_date"}},{"kind":"Field","name":{"kind":"Name","value":"death_date"}},{"kind":"Field","name":{"kind":"Name","value":"age"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"StudioFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}}]}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ScenePerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SceneFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"release_date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"as"}},{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ScenePerformerFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"submissions"}},{"kind":"Field","name":{"kind":"Name","value":"reports"}},{"kind":"Field","name":{"kind":"Name","value":"user_submitted"}},{"kind":"Field","name":{"kind":"Name","value":"user_reported"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FingerprintFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Fingerprint"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EditFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Edit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"target_type"}},{"kind":"Field","name":{"kind":"Name","value":"operation"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"bot"}},{"kind":"Field","name":{"kind":"Name","value":"applied"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}},{"kind":"Field","name":{"kind":"Name","value":"closed"}},{"kind":"Field","name":{"kind":"Name","value":"expires"}},{"kind":"Field","name":{"kind":"Name","value":"update_count"}},{"kind":"Field","name":{"kind":"Name","value":"updatable"}},{"kind":"Field","name":{"kind":"Name","value":"vote_count"}},{"kind":"Field","name":{"kind":"Name","value":"destructive"}},{"kind":"Field","name":{"kind":"Name","value":"comments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CommentFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"votes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"vote"}}]}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"target"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"added_tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"old_details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"merge_sources"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"options"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"set_modify_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"set_merge_aliases"}}]}}]}}]} as unknown as DocumentNode; export const SearchTagFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SearchTagFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}}]} as unknown as DocumentNode; export const ActivateNewUserDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ActivateNewUser"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ActivateNewUserInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activateNewUser"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; export const AddImageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"AddImage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"imageData"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ImageCreateInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"imageCreate"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"imageData"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}}]}}]} as unknown as DocumentNode; export const AddSceneDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"AddScene"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sceneData"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SceneCreateInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"sceneCreate"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sceneData"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"release_date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}}]}}]}}]} as unknown as DocumentNode; export const AddSiteDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"AddSite"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"siteData"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SiteCreateInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"siteCreate"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"siteData"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"regex"}},{"kind":"Field","name":{"kind":"Name","value":"valid_types"}}]}}]}}]} as unknown as DocumentNode; export const AddStudioDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"AddStudio"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"studioData"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"StudioCreateInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"studioCreate"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"studioData"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]}}]} as unknown as DocumentNode; export const AddTagCategoryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"AddTagCategory"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"categoryData"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TagCategoryCreateInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"tagCategoryCreate"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"categoryData"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"group"}}]}}]}}]} as unknown as DocumentNode; export const AddUserDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"AddUser"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"userData"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UserCreateInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"userCreate"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"userData"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"roles"}}]}}]}}]} as unknown as DocumentNode; export const AmendEditDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"AmendEdit"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"AmendEditInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"amendEdit"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EditFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CommentFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EditComment"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"comment"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TagFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"merged_into_id"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birth_date"}},{"kind":"Field","name":{"kind":"Name","value":"death_date"}},{"kind":"Field","name":{"kind":"Name","value":"age"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"StudioFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}}]}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ScenePerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SceneFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"release_date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"as"}},{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ScenePerformerFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"submissions"}},{"kind":"Field","name":{"kind":"Name","value":"reports"}},{"kind":"Field","name":{"kind":"Name","value":"user_submitted"}},{"kind":"Field","name":{"kind":"Name","value":"user_reported"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FingerprintFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Fingerprint"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EditFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Edit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"target_type"}},{"kind":"Field","name":{"kind":"Name","value":"operation"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"bot"}},{"kind":"Field","name":{"kind":"Name","value":"applied"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}},{"kind":"Field","name":{"kind":"Name","value":"closed"}},{"kind":"Field","name":{"kind":"Name","value":"expires"}},{"kind":"Field","name":{"kind":"Name","value":"update_count"}},{"kind":"Field","name":{"kind":"Name","value":"updatable"}},{"kind":"Field","name":{"kind":"Name","value":"vote_count"}},{"kind":"Field","name":{"kind":"Name","value":"destructive"}},{"kind":"Field","name":{"kind":"Name","value":"comments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CommentFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"votes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"vote"}}]}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"target"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"added_tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"old_details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"merge_sources"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"options"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"set_modify_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"set_merge_aliases"}}]}}]}}]} as unknown as DocumentNode; export const ApplyEditDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ApplyEdit"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ApplyEditInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"applyEdit"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EditFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CommentFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EditComment"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"comment"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TagFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"merged_into_id"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birth_date"}},{"kind":"Field","name":{"kind":"Name","value":"death_date"}},{"kind":"Field","name":{"kind":"Name","value":"age"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"StudioFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}}]}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ScenePerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SceneFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"release_date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"as"}},{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ScenePerformerFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"submissions"}},{"kind":"Field","name":{"kind":"Name","value":"reports"}},{"kind":"Field","name":{"kind":"Name","value":"user_submitted"}},{"kind":"Field","name":{"kind":"Name","value":"user_reported"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FingerprintFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Fingerprint"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EditFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Edit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"target_type"}},{"kind":"Field","name":{"kind":"Name","value":"operation"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"bot"}},{"kind":"Field","name":{"kind":"Name","value":"applied"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}},{"kind":"Field","name":{"kind":"Name","value":"closed"}},{"kind":"Field","name":{"kind":"Name","value":"expires"}},{"kind":"Field","name":{"kind":"Name","value":"update_count"}},{"kind":"Field","name":{"kind":"Name","value":"updatable"}},{"kind":"Field","name":{"kind":"Name","value":"vote_count"}},{"kind":"Field","name":{"kind":"Name","value":"destructive"}},{"kind":"Field","name":{"kind":"Name","value":"comments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CommentFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"votes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"vote"}}]}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"target"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"added_tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"old_details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"merge_sources"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"options"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"set_modify_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"set_merge_aliases"}}]}}]}}]} as unknown as DocumentNode; export const CancelEditDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CancelEdit"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CancelEditInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"cancelEdit"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"target_type"}},{"kind":"Field","name":{"kind":"Name","value":"operation"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"applied"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"target"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"merge_sources"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}}]}}]}}]}}]} as unknown as DocumentNode; export const ChangePasswordDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ChangePassword"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"userData"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UserChangePasswordInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"changePassword"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"userData"}}}]}]}}]} as unknown as DocumentNode; export const ConfirmChangeEmailDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ConfirmChangeEmail"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"token"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"confirmChangeEmail"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"token"},"value":{"kind":"Variable","name":{"kind":"Name","value":"token"}}}]}]}}]} as unknown as DocumentNode; export const DeleteDraftDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteDraft"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"destroyDraft"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}]}]}}]} as unknown as DocumentNode; export const DeleteEditDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteEdit"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DeleteEditInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteEdit"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}]}]}}]} as unknown as DocumentNode; export const DeleteFingerprintSubmissionsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteFingerprintSubmissions"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DeleteFingerprintSubmissionsInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"sceneDeleteFingerprintSubmissions"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}]}]}}]} as unknown as DocumentNode; export const DeleteSceneDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteScene"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SceneDestroyInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"sceneDestroy"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}]}]}}]} as unknown as DocumentNode; export const DeleteSiteDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteSite"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SiteDestroyInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"siteDestroy"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}]}]}}]} as unknown as DocumentNode; export const DeleteStudioDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteStudio"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"StudioDestroyInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"studioDestroy"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}]}]}}]} as unknown as DocumentNode; export const DeleteTagCategoryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteTagCategory"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TagCategoryDestroyInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"tagCategoryDestroy"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}]}]}}]} as unknown as DocumentNode; export const DeleteUserDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteUser"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UserDestroyInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"userDestroy"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}]}]}}]} as unknown as DocumentNode; export const EditCommentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"EditComment"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"EditCommentInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"editComment"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"comments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CommentFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CommentFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EditComment"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"comment"}}]}}]} as unknown as DocumentNode; export const FavoritePerformerDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"FavoritePerformer"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"favorite"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"favoritePerformer"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}},{"kind":"Argument","name":{"kind":"Name","value":"favorite"},"value":{"kind":"Variable","name":{"kind":"Name","value":"favorite"}}}]}]}}]} as unknown as DocumentNode; export const FavoriteStudioDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"FavoriteStudio"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"favorite"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"favoriteStudio"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}},{"kind":"Argument","name":{"kind":"Name","value":"favorite"},"value":{"kind":"Variable","name":{"kind":"Name","value":"favorite"}}}]}]}}]} as unknown as DocumentNode; export const GenerateInviteCodesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"GenerateInviteCodes"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"GenerateInviteCodeInput"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"generateInviteCodes"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}]}]}}]} as unknown as DocumentNode; export const GrantInviteDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"GrantInvite"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GrantInviteInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"grantInvite"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}]}]}}]} as unknown as DocumentNode; export const MarkNotificationReadDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"MarkNotificationRead"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"notification"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"MarkNotificationReadInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"markNotificationsRead"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"notification"},"value":{"kind":"Variable","name":{"kind":"Name","value":"notification"}}}]}]}}]} as unknown as DocumentNode; export const MarkNotificationsReadDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"MarkNotificationsRead"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"markNotificationsRead"}}]}}]} as unknown as DocumentNode; export const MoveFingerprintSubmissionsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"MoveFingerprintSubmissions"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"MoveFingerprintSubmissionsInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"sceneMoveFingerprintSubmissions"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}]}]}}]} as unknown as DocumentNode; export const NewUserDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"NewUser"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NewUserInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"newUser"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}]}]}}]} as unknown as DocumentNode; export const PerformerEditDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"PerformerEdit"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"performerData"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEditInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performerEdit"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"performerData"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EditFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CommentFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EditComment"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"comment"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TagFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"merged_into_id"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birth_date"}},{"kind":"Field","name":{"kind":"Name","value":"death_date"}},{"kind":"Field","name":{"kind":"Name","value":"age"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"StudioFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}}]}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ScenePerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SceneFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"release_date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"as"}},{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ScenePerformerFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"submissions"}},{"kind":"Field","name":{"kind":"Name","value":"reports"}},{"kind":"Field","name":{"kind":"Name","value":"user_submitted"}},{"kind":"Field","name":{"kind":"Name","value":"user_reported"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FingerprintFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Fingerprint"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EditFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Edit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"target_type"}},{"kind":"Field","name":{"kind":"Name","value":"operation"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"bot"}},{"kind":"Field","name":{"kind":"Name","value":"applied"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}},{"kind":"Field","name":{"kind":"Name","value":"closed"}},{"kind":"Field","name":{"kind":"Name","value":"expires"}},{"kind":"Field","name":{"kind":"Name","value":"update_count"}},{"kind":"Field","name":{"kind":"Name","value":"updatable"}},{"kind":"Field","name":{"kind":"Name","value":"vote_count"}},{"kind":"Field","name":{"kind":"Name","value":"destructive"}},{"kind":"Field","name":{"kind":"Name","value":"comments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CommentFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"votes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"vote"}}]}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"target"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"added_tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"old_details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"merge_sources"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"options"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"set_modify_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"set_merge_aliases"}}]}}]}}]} as unknown as DocumentNode; export const PerformerEditUpdateDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"PerformerEditUpdate"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"performerData"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEditInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performerEditUpdate"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}},{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"performerData"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EditFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CommentFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EditComment"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"comment"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TagFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"merged_into_id"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birth_date"}},{"kind":"Field","name":{"kind":"Name","value":"death_date"}},{"kind":"Field","name":{"kind":"Name","value":"age"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"StudioFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}}]}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ScenePerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SceneFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"release_date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"as"}},{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ScenePerformerFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"submissions"}},{"kind":"Field","name":{"kind":"Name","value":"reports"}},{"kind":"Field","name":{"kind":"Name","value":"user_submitted"}},{"kind":"Field","name":{"kind":"Name","value":"user_reported"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FingerprintFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Fingerprint"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EditFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Edit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"target_type"}},{"kind":"Field","name":{"kind":"Name","value":"operation"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"bot"}},{"kind":"Field","name":{"kind":"Name","value":"applied"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}},{"kind":"Field","name":{"kind":"Name","value":"closed"}},{"kind":"Field","name":{"kind":"Name","value":"expires"}},{"kind":"Field","name":{"kind":"Name","value":"update_count"}},{"kind":"Field","name":{"kind":"Name","value":"updatable"}},{"kind":"Field","name":{"kind":"Name","value":"vote_count"}},{"kind":"Field","name":{"kind":"Name","value":"destructive"}},{"kind":"Field","name":{"kind":"Name","value":"comments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CommentFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"votes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"vote"}}]}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"target"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"added_tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"old_details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"merge_sources"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"options"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"set_modify_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"set_merge_aliases"}}]}}]}}]} as unknown as DocumentNode; export const RegenerateApiKeyDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"RegenerateAPIKey"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"user_id"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"regenerateAPIKey"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"userID"},"value":{"kind":"Variable","name":{"kind":"Name","value":"user_id"}}}]}]}}]} as unknown as DocumentNode; export const RequestChangeEmailDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"RequestChangeEmail"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"requestChangeEmail"}}]}}]} as unknown as DocumentNode; export const RescindInviteCodeDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"RescindInviteCode"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"code"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"rescindInviteCode"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"code"},"value":{"kind":"Variable","name":{"kind":"Name","value":"code"}}}]}]}}]} as unknown as DocumentNode; export const ResetPasswordDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ResetPassword"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ResetPasswordInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"resetPassword"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}]}]}}]} as unknown as DocumentNode; export const RevokeInviteDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"RevokeInvite"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"RevokeInviteInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"revokeInvite"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}]}]}}]} as unknown as DocumentNode; export const SceneEditDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SceneEdit"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sceneData"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEditInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"sceneEdit"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sceneData"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EditFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CommentFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EditComment"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"comment"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TagFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"merged_into_id"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birth_date"}},{"kind":"Field","name":{"kind":"Name","value":"death_date"}},{"kind":"Field","name":{"kind":"Name","value":"age"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"StudioFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}}]}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ScenePerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SceneFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"release_date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"as"}},{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ScenePerformerFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"submissions"}},{"kind":"Field","name":{"kind":"Name","value":"reports"}},{"kind":"Field","name":{"kind":"Name","value":"user_submitted"}},{"kind":"Field","name":{"kind":"Name","value":"user_reported"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FingerprintFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Fingerprint"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EditFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Edit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"target_type"}},{"kind":"Field","name":{"kind":"Name","value":"operation"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"bot"}},{"kind":"Field","name":{"kind":"Name","value":"applied"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}},{"kind":"Field","name":{"kind":"Name","value":"closed"}},{"kind":"Field","name":{"kind":"Name","value":"expires"}},{"kind":"Field","name":{"kind":"Name","value":"update_count"}},{"kind":"Field","name":{"kind":"Name","value":"updatable"}},{"kind":"Field","name":{"kind":"Name","value":"vote_count"}},{"kind":"Field","name":{"kind":"Name","value":"destructive"}},{"kind":"Field","name":{"kind":"Name","value":"comments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CommentFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"votes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"vote"}}]}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"target"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"added_tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"old_details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"merge_sources"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"options"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"set_modify_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"set_merge_aliases"}}]}}]}}]} as unknown as DocumentNode; export const SceneEditUpdateDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SceneEditUpdate"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sceneData"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEditInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"sceneEditUpdate"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}},{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sceneData"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EditFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CommentFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EditComment"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"comment"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TagFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"merged_into_id"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birth_date"}},{"kind":"Field","name":{"kind":"Name","value":"death_date"}},{"kind":"Field","name":{"kind":"Name","value":"age"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"StudioFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}}]}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ScenePerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SceneFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"release_date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"as"}},{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ScenePerformerFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"submissions"}},{"kind":"Field","name":{"kind":"Name","value":"reports"}},{"kind":"Field","name":{"kind":"Name","value":"user_submitted"}},{"kind":"Field","name":{"kind":"Name","value":"user_reported"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FingerprintFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Fingerprint"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EditFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Edit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"target_type"}},{"kind":"Field","name":{"kind":"Name","value":"operation"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"bot"}},{"kind":"Field","name":{"kind":"Name","value":"applied"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}},{"kind":"Field","name":{"kind":"Name","value":"closed"}},{"kind":"Field","name":{"kind":"Name","value":"expires"}},{"kind":"Field","name":{"kind":"Name","value":"update_count"}},{"kind":"Field","name":{"kind":"Name","value":"updatable"}},{"kind":"Field","name":{"kind":"Name","value":"vote_count"}},{"kind":"Field","name":{"kind":"Name","value":"destructive"}},{"kind":"Field","name":{"kind":"Name","value":"comments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CommentFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"votes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"vote"}}]}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"target"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"added_tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"old_details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"merge_sources"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"options"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"set_modify_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"set_merge_aliases"}}]}}]}}]} as unknown as DocumentNode; export const StudioEditDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"StudioEdit"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"studioData"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEditInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"studioEdit"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"studioData"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EditFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CommentFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EditComment"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"comment"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TagFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"merged_into_id"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birth_date"}},{"kind":"Field","name":{"kind":"Name","value":"death_date"}},{"kind":"Field","name":{"kind":"Name","value":"age"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"StudioFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}}]}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ScenePerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SceneFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"release_date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"as"}},{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ScenePerformerFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"submissions"}},{"kind":"Field","name":{"kind":"Name","value":"reports"}},{"kind":"Field","name":{"kind":"Name","value":"user_submitted"}},{"kind":"Field","name":{"kind":"Name","value":"user_reported"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FingerprintFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Fingerprint"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EditFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Edit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"target_type"}},{"kind":"Field","name":{"kind":"Name","value":"operation"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"bot"}},{"kind":"Field","name":{"kind":"Name","value":"applied"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}},{"kind":"Field","name":{"kind":"Name","value":"closed"}},{"kind":"Field","name":{"kind":"Name","value":"expires"}},{"kind":"Field","name":{"kind":"Name","value":"update_count"}},{"kind":"Field","name":{"kind":"Name","value":"updatable"}},{"kind":"Field","name":{"kind":"Name","value":"vote_count"}},{"kind":"Field","name":{"kind":"Name","value":"destructive"}},{"kind":"Field","name":{"kind":"Name","value":"comments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CommentFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"votes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"vote"}}]}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"target"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"added_tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"old_details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"merge_sources"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"options"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"set_modify_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"set_merge_aliases"}}]}}]}}]} as unknown as DocumentNode; export const StudioEditUpdateDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"StudioEditUpdate"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"studioData"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEditInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"studioEditUpdate"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}},{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"studioData"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EditFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CommentFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EditComment"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"comment"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TagFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"merged_into_id"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birth_date"}},{"kind":"Field","name":{"kind":"Name","value":"death_date"}},{"kind":"Field","name":{"kind":"Name","value":"age"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"StudioFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}}]}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ScenePerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SceneFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"release_date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"as"}},{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ScenePerformerFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"submissions"}},{"kind":"Field","name":{"kind":"Name","value":"reports"}},{"kind":"Field","name":{"kind":"Name","value":"user_submitted"}},{"kind":"Field","name":{"kind":"Name","value":"user_reported"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FingerprintFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Fingerprint"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EditFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Edit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"target_type"}},{"kind":"Field","name":{"kind":"Name","value":"operation"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"bot"}},{"kind":"Field","name":{"kind":"Name","value":"applied"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}},{"kind":"Field","name":{"kind":"Name","value":"closed"}},{"kind":"Field","name":{"kind":"Name","value":"expires"}},{"kind":"Field","name":{"kind":"Name","value":"update_count"}},{"kind":"Field","name":{"kind":"Name","value":"updatable"}},{"kind":"Field","name":{"kind":"Name","value":"vote_count"}},{"kind":"Field","name":{"kind":"Name","value":"destructive"}},{"kind":"Field","name":{"kind":"Name","value":"comments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CommentFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"votes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"vote"}}]}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"target"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"added_tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"old_details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"merge_sources"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"options"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"set_modify_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"set_merge_aliases"}}]}}]}}]} as unknown as DocumentNode; export const TagEditDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"TagEdit"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"tagData"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TagEditInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"tagEdit"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"tagData"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EditFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CommentFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EditComment"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"comment"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TagFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"merged_into_id"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birth_date"}},{"kind":"Field","name":{"kind":"Name","value":"death_date"}},{"kind":"Field","name":{"kind":"Name","value":"age"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"StudioFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}}]}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ScenePerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SceneFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"release_date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"as"}},{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ScenePerformerFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"submissions"}},{"kind":"Field","name":{"kind":"Name","value":"reports"}},{"kind":"Field","name":{"kind":"Name","value":"user_submitted"}},{"kind":"Field","name":{"kind":"Name","value":"user_reported"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FingerprintFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Fingerprint"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EditFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Edit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"target_type"}},{"kind":"Field","name":{"kind":"Name","value":"operation"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"bot"}},{"kind":"Field","name":{"kind":"Name","value":"applied"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}},{"kind":"Field","name":{"kind":"Name","value":"closed"}},{"kind":"Field","name":{"kind":"Name","value":"expires"}},{"kind":"Field","name":{"kind":"Name","value":"update_count"}},{"kind":"Field","name":{"kind":"Name","value":"updatable"}},{"kind":"Field","name":{"kind":"Name","value":"vote_count"}},{"kind":"Field","name":{"kind":"Name","value":"destructive"}},{"kind":"Field","name":{"kind":"Name","value":"comments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CommentFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"votes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"vote"}}]}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"target"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"added_tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"old_details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"merge_sources"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"options"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"set_modify_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"set_merge_aliases"}}]}}]}}]} as unknown as DocumentNode; export const TagEditUpdateDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"TagEditUpdate"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"tagData"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TagEditInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"tagEditUpdate"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}},{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"tagData"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EditFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CommentFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EditComment"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"comment"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TagFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"merged_into_id"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birth_date"}},{"kind":"Field","name":{"kind":"Name","value":"death_date"}},{"kind":"Field","name":{"kind":"Name","value":"age"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"StudioFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}}]}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ScenePerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SceneFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"release_date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"as"}},{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ScenePerformerFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"submissions"}},{"kind":"Field","name":{"kind":"Name","value":"reports"}},{"kind":"Field","name":{"kind":"Name","value":"user_submitted"}},{"kind":"Field","name":{"kind":"Name","value":"user_reported"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FingerprintFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Fingerprint"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EditFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Edit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"target_type"}},{"kind":"Field","name":{"kind":"Name","value":"operation"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"bot"}},{"kind":"Field","name":{"kind":"Name","value":"applied"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}},{"kind":"Field","name":{"kind":"Name","value":"closed"}},{"kind":"Field","name":{"kind":"Name","value":"expires"}},{"kind":"Field","name":{"kind":"Name","value":"update_count"}},{"kind":"Field","name":{"kind":"Name","value":"updatable"}},{"kind":"Field","name":{"kind":"Name","value":"vote_count"}},{"kind":"Field","name":{"kind":"Name","value":"destructive"}},{"kind":"Field","name":{"kind":"Name","value":"comments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CommentFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"votes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"vote"}}]}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"target"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"added_tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"old_details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"merge_sources"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"options"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"set_modify_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"set_merge_aliases"}}]}}]}}]} as unknown as DocumentNode; export const UnmatchFingerprintDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UnmatchFingerprint"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"scene_id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"algorithm"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"FingerprintAlgorithm"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"hash"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"FingerprintHash"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"duration"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","alias":{"kind":"Name","value":"unmatchFingerprint"},"name":{"kind":"Name","value":"submitFingerprint"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"vote"},"value":{"kind":"EnumValue","value":"REMOVE"}},{"kind":"ObjectField","name":{"kind":"Name","value":"scene_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"scene_id"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"fingerprint"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"hash"},"value":{"kind":"Variable","name":{"kind":"Name","value":"hash"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"algorithm"},"value":{"kind":"Variable","name":{"kind":"Name","value":"algorithm"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"duration"},"value":{"kind":"Variable","name":{"kind":"Name","value":"duration"}}}]}}]}}]}]}}]} as unknown as DocumentNode; export const UpdateNotificationSubscriptionsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateNotificationSubscriptions"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"subscriptions"}},"type":{"kind":"NonNullType","type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationEnum"}}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateNotificationSubscriptions"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"subscriptions"},"value":{"kind":"Variable","name":{"kind":"Name","value":"subscriptions"}}}]}]}}]} as unknown as DocumentNode; export const UpdateSceneDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateScene"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"updateData"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SceneUpdateInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"sceneUpdate"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"updateData"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"release_date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}}]}}]}}]} as unknown as DocumentNode; export const UpdateSiteDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateSite"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"siteData"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SiteUpdateInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"siteUpdate"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"siteData"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"regex"}},{"kind":"Field","name":{"kind":"Name","value":"valid_types"}}]}}]}}]} as unknown as DocumentNode; export const UpdateStudioDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateStudio"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"StudioUpdateInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"studioUpdate"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"StudioFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}}]}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}}]} as unknown as DocumentNode; export const UpdateTagCategoryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateTagCategory"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"categoryData"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TagCategoryUpdateInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"tagCategoryUpdate"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"categoryData"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"group"}}]}}]}}]} as unknown as DocumentNode; export const UpdateUserDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateUser"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"userData"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UserUpdateInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"userUpdate"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"userData"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"roles"}}]}}]}}]} as unknown as DocumentNode; export const ValidateChangeEmailDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ValidateChangeEmail"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"token"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"email"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"validateChangeEmail"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"token"},"value":{"kind":"Variable","name":{"kind":"Name","value":"token"}}},{"kind":"Argument","name":{"kind":"Name","value":"email"},"value":{"kind":"Variable","name":{"kind":"Name","value":"email"}}}]}]}}]} as unknown as DocumentNode; export const VoteDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"Vote"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"EditVoteInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"editVote"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EditFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CommentFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EditComment"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"comment"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TagFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"merged_into_id"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birth_date"}},{"kind":"Field","name":{"kind":"Name","value":"death_date"}},{"kind":"Field","name":{"kind":"Name","value":"age"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"StudioFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}}]}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ScenePerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SceneFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"release_date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"as"}},{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ScenePerformerFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"submissions"}},{"kind":"Field","name":{"kind":"Name","value":"reports"}},{"kind":"Field","name":{"kind":"Name","value":"user_submitted"}},{"kind":"Field","name":{"kind":"Name","value":"user_reported"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FingerprintFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Fingerprint"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EditFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Edit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"target_type"}},{"kind":"Field","name":{"kind":"Name","value":"operation"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"bot"}},{"kind":"Field","name":{"kind":"Name","value":"applied"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}},{"kind":"Field","name":{"kind":"Name","value":"closed"}},{"kind":"Field","name":{"kind":"Name","value":"expires"}},{"kind":"Field","name":{"kind":"Name","value":"update_count"}},{"kind":"Field","name":{"kind":"Name","value":"updatable"}},{"kind":"Field","name":{"kind":"Name","value":"vote_count"}},{"kind":"Field","name":{"kind":"Name","value":"destructive"}},{"kind":"Field","name":{"kind":"Name","value":"comments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CommentFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"votes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"vote"}}]}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"target"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"added_tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"old_details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"merge_sources"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"options"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"set_modify_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"set_merge_aliases"}}]}}]}}]} as unknown as DocumentNode; export const CategoriesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Categories"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"queryTagCategories"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"count"}},{"kind":"Field","name":{"kind":"Name","value":"tag_categories"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"group"}}]}}]}}]}}]} as unknown as DocumentNode; export const CategoryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Category"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findTagCategory"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"group"}}]}}]}}]} as unknown as DocumentNode; export const ConfigDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Config"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getConfig"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edit_update_limit"}},{"kind":"Field","name":{"kind":"Name","value":"host_url"}},{"kind":"Field","name":{"kind":"Name","value":"require_invite"}},{"kind":"Field","name":{"kind":"Name","value":"require_activation"}},{"kind":"Field","name":{"kind":"Name","value":"vote_promotion_threshold"}},{"kind":"Field","name":{"kind":"Name","value":"vote_application_threshold"}},{"kind":"Field","name":{"kind":"Name","value":"voting_period"}},{"kind":"Field","name":{"kind":"Name","value":"min_destructive_voting_period"}},{"kind":"Field","name":{"kind":"Name","value":"vote_cron_interval"}},{"kind":"Field","name":{"kind":"Name","value":"guidelines_url"}},{"kind":"Field","name":{"kind":"Name","value":"require_scene_draft"}},{"kind":"Field","name":{"kind":"Name","value":"require_tag_role"}}]}}]}}]} as unknown as DocumentNode; export const DraftDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Draft"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findDraft"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"expires"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerDraft"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"urls"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"measurements"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"tattoos"}},{"kind":"Field","name":{"kind":"Name","value":"piercings"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"image"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneDraft"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"urls"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"DraftEntity"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","alias":{"kind":"Name","value":"draftID"},"name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"DraftEntity"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","alias":{"kind":"Name","value":"draftID"},"name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"DraftEntity"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","alias":{"kind":"Name","value":"draftID"},"name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}}]}},{"kind":"Field","name":{"kind":"Name","value":"image"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"StudioFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}}]}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"merged_into_id"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birth_date"}},{"kind":"Field","name":{"kind":"Name","value":"death_date"}},{"kind":"Field","name":{"kind":"Name","value":"age"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TagFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}}]} as unknown as DocumentNode; export const DraftsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Drafts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findDrafts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"expires"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerDraft"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneDraft"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}}]}}]}}]}}]}}]} as unknown as DocumentNode; export const EditDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Edit"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findEdit"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EditFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CommentFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EditComment"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"comment"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TagFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"merged_into_id"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birth_date"}},{"kind":"Field","name":{"kind":"Name","value":"death_date"}},{"kind":"Field","name":{"kind":"Name","value":"age"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"StudioFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}}]}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ScenePerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SceneFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"release_date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"as"}},{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ScenePerformerFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"submissions"}},{"kind":"Field","name":{"kind":"Name","value":"reports"}},{"kind":"Field","name":{"kind":"Name","value":"user_submitted"}},{"kind":"Field","name":{"kind":"Name","value":"user_reported"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FingerprintFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Fingerprint"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EditFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Edit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"target_type"}},{"kind":"Field","name":{"kind":"Name","value":"operation"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"bot"}},{"kind":"Field","name":{"kind":"Name","value":"applied"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}},{"kind":"Field","name":{"kind":"Name","value":"closed"}},{"kind":"Field","name":{"kind":"Name","value":"expires"}},{"kind":"Field","name":{"kind":"Name","value":"update_count"}},{"kind":"Field","name":{"kind":"Name","value":"updatable"}},{"kind":"Field","name":{"kind":"Name","value":"vote_count"}},{"kind":"Field","name":{"kind":"Name","value":"destructive"}},{"kind":"Field","name":{"kind":"Name","value":"comments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CommentFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"votes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"vote"}}]}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"target"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"added_tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"old_details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"merge_sources"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"options"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"set_modify_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"set_merge_aliases"}}]}}]}}]} as unknown as DocumentNode; export const EditUpdateDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EditUpdate"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findEdit"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"target_type"}},{"kind":"Field","name":{"kind":"Name","value":"operation"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"applied"}},{"kind":"Field","name":{"kind":"Name","value":"closed"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}},{"kind":"Field","name":{"kind":"Name","value":"updatable"}},{"kind":"Field","name":{"kind":"Name","value":"update_count"}},{"kind":"Field","name":{"kind":"Name","value":"vote_count"}},{"kind":"Field","name":{"kind":"Name","value":"merge_sources"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"options"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"set_modify_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"set_merge_aliases"}}]}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"target"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ScenePerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TagFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"merged_into_id"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birth_date"}},{"kind":"Field","name":{"kind":"Name","value":"death_date"}},{"kind":"Field","name":{"kind":"Name","value":"age"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"StudioFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}}]}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SceneFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"release_date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"as"}},{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ScenePerformerFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"submissions"}},{"kind":"Field","name":{"kind":"Name","value":"reports"}},{"kind":"Field","name":{"kind":"Name","value":"user_submitted"}},{"kind":"Field","name":{"kind":"Name","value":"user_reported"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FingerprintFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Fingerprint"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}}]}}]} as unknown as DocumentNode; export const EditsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Edits"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"EditQueryInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"queryEdits"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"count"}},{"kind":"Field","name":{"kind":"Name","value":"edits"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EditFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CommentFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EditComment"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"comment"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TagFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"merged_into_id"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birth_date"}},{"kind":"Field","name":{"kind":"Name","value":"death_date"}},{"kind":"Field","name":{"kind":"Name","value":"age"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"StudioFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}}]}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ScenePerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SceneFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"release_date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"as"}},{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ScenePerformerFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"submissions"}},{"kind":"Field","name":{"kind":"Name","value":"reports"}},{"kind":"Field","name":{"kind":"Name","value":"user_submitted"}},{"kind":"Field","name":{"kind":"Name","value":"user_reported"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FingerprintFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Fingerprint"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EditFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Edit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"target_type"}},{"kind":"Field","name":{"kind":"Name","value":"operation"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"bot"}},{"kind":"Field","name":{"kind":"Name","value":"applied"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}},{"kind":"Field","name":{"kind":"Name","value":"closed"}},{"kind":"Field","name":{"kind":"Name","value":"expires"}},{"kind":"Field","name":{"kind":"Name","value":"update_count"}},{"kind":"Field","name":{"kind":"Name","value":"updatable"}},{"kind":"Field","name":{"kind":"Name","value":"vote_count"}},{"kind":"Field","name":{"kind":"Name","value":"destructive"}},{"kind":"Field","name":{"kind":"Name","value":"comments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CommentFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"votes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"vote"}}]}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"target"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"added_tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"old_details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"merge_sources"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"options"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"set_modify_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"set_merge_aliases"}}]}}]}}]} as unknown as DocumentNode; export const FullPerformerDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FullPerformer"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findPerformer"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}},{"kind":"Field","name":{"kind":"Name","value":"studios"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"scene_count"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"merged_into_id"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birth_date"}},{"kind":"Field","name":{"kind":"Name","value":"death_date"}},{"kind":"Field","name":{"kind":"Name","value":"age"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}}]} as unknown as DocumentNode; export const MeDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"roles"}}]}}]}}]} as unknown as DocumentNode; export const ModAuditsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ModAudits"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ModAuditQueryInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"queryModAudits"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"count"}},{"kind":"Field","name":{"kind":"Name","value":"audits"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"action"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"target_id"}},{"kind":"Field","name":{"kind":"Name","value":"target_type"}},{"kind":"Field","name":{"kind":"Name","value":"data"}},{"kind":"Field","name":{"kind":"Name","value":"reason"}},{"kind":"Field","name":{"kind":"Name","value":"created_at"}}]}}]}}]}}]} as unknown as DocumentNode; export const PendingEditsCountDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"PendingEditsCount"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"type"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TargetTypeEnum"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"queryEdits"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"target_type"},"value":{"kind":"Variable","name":{"kind":"Name","value":"type"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"target_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"status"},"value":{"kind":"EnumValue","value":"PENDING"}},{"kind":"ObjectField","name":{"kind":"Name","value":"per_page"},"value":{"kind":"IntValue","value":"1"}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"count"}}]}}]}}]} as unknown as DocumentNode; export const PerformerDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Performer"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findPerformer"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"merged_into_id"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birth_date"}},{"kind":"Field","name":{"kind":"Name","value":"death_date"}},{"kind":"Field","name":{"kind":"Name","value":"age"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}}]} as unknown as DocumentNode; export const PerformersDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Performers"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerQueryInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"queryPerformers"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"count"}},{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birth_date"}},{"kind":"Field","name":{"kind":"Name","value":"age"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}}]} as unknown as DocumentNode; export const PublicUserDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"PublicUser"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"name"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findUser"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"username"},"value":{"kind":"Variable","name":{"kind":"Name","value":"name"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"vote_count"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"accept"}},{"kind":"Field","name":{"kind":"Name","value":"reject"}},{"kind":"Field","name":{"kind":"Name","value":"immediate_accept"}},{"kind":"Field","name":{"kind":"Name","value":"immediate_reject"}},{"kind":"Field","name":{"kind":"Name","value":"abstain"}}]}},{"kind":"Field","name":{"kind":"Name","value":"edit_count"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"immediate_accepted"}},{"kind":"Field","name":{"kind":"Name","value":"immediate_rejected"}},{"kind":"Field","name":{"kind":"Name","value":"accepted"}},{"kind":"Field","name":{"kind":"Name","value":"rejected"}},{"kind":"Field","name":{"kind":"Name","value":"failed"}},{"kind":"Field","name":{"kind":"Name","value":"canceled"}},{"kind":"Field","name":{"kind":"Name","value":"pending"}}]}}]}}]}}]} as unknown as DocumentNode; export const QueryExistingPerformerDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"QueryExistingPerformer"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"QueryExistingPerformerInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"queryExistingPerformer"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"edits"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EditFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CommentFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EditComment"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"comment"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TagFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"merged_into_id"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birth_date"}},{"kind":"Field","name":{"kind":"Name","value":"death_date"}},{"kind":"Field","name":{"kind":"Name","value":"age"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"StudioFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}}]}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ScenePerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SceneFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"release_date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"as"}},{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ScenePerformerFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"submissions"}},{"kind":"Field","name":{"kind":"Name","value":"reports"}},{"kind":"Field","name":{"kind":"Name","value":"user_submitted"}},{"kind":"Field","name":{"kind":"Name","value":"user_reported"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FingerprintFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Fingerprint"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EditFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Edit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"target_type"}},{"kind":"Field","name":{"kind":"Name","value":"operation"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"bot"}},{"kind":"Field","name":{"kind":"Name","value":"applied"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}},{"kind":"Field","name":{"kind":"Name","value":"closed"}},{"kind":"Field","name":{"kind":"Name","value":"expires"}},{"kind":"Field","name":{"kind":"Name","value":"update_count"}},{"kind":"Field","name":{"kind":"Name","value":"updatable"}},{"kind":"Field","name":{"kind":"Name","value":"vote_count"}},{"kind":"Field","name":{"kind":"Name","value":"destructive"}},{"kind":"Field","name":{"kind":"Name","value":"comments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CommentFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"votes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"vote"}}]}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"target"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"added_tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"old_details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"merge_sources"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"options"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"set_modify_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"set_merge_aliases"}}]}}]}}]} as unknown as DocumentNode; export const QueryExistingSceneDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"QueryExistingScene"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"QueryExistingSceneInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"queryExistingScene"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"scenes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"edits"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EditFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ScenePerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CommentFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EditComment"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"comment"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TagFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"merged_into_id"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birth_date"}},{"kind":"Field","name":{"kind":"Name","value":"death_date"}},{"kind":"Field","name":{"kind":"Name","value":"age"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"StudioFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}}]}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SceneFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"release_date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"as"}},{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ScenePerformerFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"submissions"}},{"kind":"Field","name":{"kind":"Name","value":"reports"}},{"kind":"Field","name":{"kind":"Name","value":"user_submitted"}},{"kind":"Field","name":{"kind":"Name","value":"user_reported"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FingerprintFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Fingerprint"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EditFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Edit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"target_type"}},{"kind":"Field","name":{"kind":"Name","value":"operation"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"bot"}},{"kind":"Field","name":{"kind":"Name","value":"applied"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}},{"kind":"Field","name":{"kind":"Name","value":"closed"}},{"kind":"Field","name":{"kind":"Name","value":"expires"}},{"kind":"Field","name":{"kind":"Name","value":"update_count"}},{"kind":"Field","name":{"kind":"Name","value":"updatable"}},{"kind":"Field","name":{"kind":"Name","value":"vote_count"}},{"kind":"Field","name":{"kind":"Name","value":"destructive"}},{"kind":"Field","name":{"kind":"Name","value":"comments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CommentFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"votes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"vote"}}]}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"target"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"added_tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"old_details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"merge_sources"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"options"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"set_modify_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"set_merge_aliases"}}]}}]}}]} as unknown as DocumentNode; export const NotificationsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Notifications"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"QueryNotificationsInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"queryNotifications"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"count"}},{"kind":"Field","name":{"kind":"Name","value":"notifications"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"read"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"__typename"}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FavoritePerformerScene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"scene"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FavoritePerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edit"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EditFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FavoriteStudioScene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"scene"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FavoriteStudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edit"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EditFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"CommentOwnEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"comment"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NotificationCommentFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"CommentCommentedEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"comment"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NotificationCommentFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"CommentVotedEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"comment"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NotificationCommentFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"DownvoteOwnEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edit"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EditFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FailedOwnEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edit"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EditFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"UpdatedEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edit"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EditFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FingerprintedSceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edit"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EditFragment"}}]}}]}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ScenePerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CommentFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EditComment"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"comment"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TagFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"merged_into_id"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birth_date"}},{"kind":"Field","name":{"kind":"Name","value":"death_date"}},{"kind":"Field","name":{"kind":"Name","value":"age"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"StudioFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}}]}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SceneFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"release_date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"as"}},{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ScenePerformerFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"submissions"}},{"kind":"Field","name":{"kind":"Name","value":"reports"}},{"kind":"Field","name":{"kind":"Name","value":"user_submitted"}},{"kind":"Field","name":{"kind":"Name","value":"user_reported"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FingerprintFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Fingerprint"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EditFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Edit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"target_type"}},{"kind":"Field","name":{"kind":"Name","value":"operation"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"bot"}},{"kind":"Field","name":{"kind":"Name","value":"applied"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}},{"kind":"Field","name":{"kind":"Name","value":"closed"}},{"kind":"Field","name":{"kind":"Name","value":"expires"}},{"kind":"Field","name":{"kind":"Name","value":"update_count"}},{"kind":"Field","name":{"kind":"Name","value":"updatable"}},{"kind":"Field","name":{"kind":"Name","value":"vote_count"}},{"kind":"Field","name":{"kind":"Name","value":"destructive"}},{"kind":"Field","name":{"kind":"Name","value":"comments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CommentFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"votes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"vote"}}]}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"target"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"added_tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tattoos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_piercings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"added_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"removed_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"draft_id"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"old_details"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birthdate"}},{"kind":"Field","name":{"kind":"Name","value":"deathdate"}},{"kind":"Field","name":{"kind":"Name","value":"ethnicity"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"eye_color"}},{"kind":"Field","name":{"kind":"Name","value":"hair_color"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"cup_size"}},{"kind":"Field","name":{"kind":"Name","value":"band_size"}},{"kind":"Field","name":{"kind":"Name","value":"waist_size"}},{"kind":"Field","name":{"kind":"Name","value":"hip_size"}},{"kind":"Field","name":{"kind":"Name","value":"breast_type"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StudioEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SceneEdit"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"added_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"as"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"added_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"removed_fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FingerprintFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"merge_sources"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PerformerFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"options"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"set_modify_aliases"}},{"kind":"Field","name":{"kind":"Name","value":"set_merge_aliases"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationCommentFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EditComment"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CommentFragment"}},{"kind":"Field","name":{"kind":"Name","value":"edit"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EditFragment"}}]}}]}}]} as unknown as DocumentNode; export const SceneDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Scene"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findScene"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SceneFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ScenePerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SceneFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"release_date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"director"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"as"}},{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ScenePerformerFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"fingerprints"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"submissions"}},{"kind":"Field","name":{"kind":"Name","value":"reports"}},{"kind":"Field","name":{"kind":"Name","value":"user_submitted"}},{"kind":"Field","name":{"kind":"Name","value":"user_reported"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}}]}}]} as unknown as DocumentNode; export const ScenePairingsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ScenePairings"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"performerId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"names"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"gender"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"GenderFilterEnum"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"favorite"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},"defaultValue":{"kind":"IntValue","value":"1"}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"per_page"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},"defaultValue":{"kind":"IntValue","value":"25"}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"direction"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SortDirectionEnum"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sort"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerSortEnum"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"fetchScenes"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"queryPerformers"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"performed_with"},"value":{"kind":"Variable","name":{"kind":"Name","value":"performerId"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"names"},"value":{"kind":"Variable","name":{"kind":"Name","value":"names"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"gender"},"value":{"kind":"Variable","name":{"kind":"Name","value":"gender"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"is_favorite"},"value":{"kind":"Variable","name":{"kind":"Name","value":"favorite"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"per_page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"per_page"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"direction"},"value":{"kind":"Variable","name":{"kind":"Name","value":"direction"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"sort"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sort"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"count"}},{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birth_date"}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"scenes"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"performed_with"},"value":{"kind":"Variable","name":{"kind":"Name","value":"performerId"}}}]}}],"directives":[{"kind":"Directive","name":{"kind":"Name","value":"include"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"if"},"value":{"kind":"Variable","name":{"kind":"Name","value":"fetchScenes"}}}]}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"date"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"release_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}}]} as unknown as DocumentNode; export const ScenesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Scenes"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SceneQueryInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"queryScenes"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"count"}},{"kind":"Field","name":{"kind":"Name","value":"scenes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"QuerySceneFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ScenePerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"QuerySceneFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"release_date"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"as"}},{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ScenePerformerFragment"}}]}}]}}]}}]} as unknown as DocumentNode; export const ScenesWithFingerprintsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ScenesWithFingerprints"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SceneQueryInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"submitted"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"queryScenes"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"count"}},{"kind":"Field","name":{"kind":"Name","value":"scenes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"QuerySceneFragment"}},{"kind":"Field","name":{"kind":"Name","value":"fingerprints"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"is_submitted"},"value":{"kind":"Variable","name":{"kind":"Name","value":"submitted"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"algorithm"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"submissions"}},{"kind":"Field","name":{"kind":"Name","value":"user_submitted"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ScenePerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"QuerySceneFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"release_date"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"as"}},{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ScenePerformerFragment"}}]}}]}}]}}]} as unknown as DocumentNode; export const ScenesWithoutCountDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ScenesWithoutCount"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SceneQueryInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"queryScenes"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"scenes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"QuerySceneFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ScenePerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"QuerySceneFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Scene"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"release_date"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"as"}},{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ScenePerformerFragment"}}]}}]}}]}}]} as unknown as DocumentNode; export const SearchAllDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"SearchAll"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"term"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}},"defaultValue":{"kind":"IntValue","value":"5"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"searchPerformers"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"term"},"value":{"kind":"Variable","name":{"kind":"Name","value":"term"}}},{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"count"}},{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SearchPerformerFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"searchScenes"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"term"},"value":{"kind":"Variable","name":{"kind":"Name","value":"term"}}},{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"count"}},{"kind":"Field","name":{"kind":"Name","value":"scenes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"release_date"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"as"}},{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}}]}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SearchPerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"scene_count"}},{"kind":"Field","name":{"kind":"Name","value":"birth_date"}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}}]} as unknown as DocumentNode; export const SearchPerformersDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"SearchPerformers"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"term"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"per_page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"filter"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerSearchFilter"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"studioId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"hasStudioId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},"defaultValue":{"kind":"BooleanValue","value":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"searchPerformers"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"term"},"value":{"kind":"Variable","name":{"kind":"Name","value":"term"}}},{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"per_page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"per_page"}}},{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"filter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"count"}},{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SearchPerformerFragment"}},{"kind":"Field","name":{"kind":"Name","value":"studios"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"studio_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"studioId"}}}],"directives":[{"kind":"Directive","name":{"kind":"Name","value":"include"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"if"},"value":{"kind":"Variable","name":{"kind":"Name","value":"hasStudioId"}}}]}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"scene_count"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"facets"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"genders"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"count"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SearchPerformerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Performer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"country"}},{"kind":"Field","name":{"kind":"Name","value":"career_start_year"}},{"kind":"Field","name":{"kind":"Name","value":"career_end_year"}},{"kind":"Field","name":{"kind":"Name","value":"scene_count"}},{"kind":"Field","name":{"kind":"Name","value":"birth_date"}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}}]} as unknown as DocumentNode; export const SearchScenesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"SearchScenes"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"term"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"per_page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"searchScenes"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"term"},"value":{"kind":"Variable","name":{"kind":"Name","value":"term"}}},{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"per_page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"per_page"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"count"}},{"kind":"Field","name":{"kind":"Name","value":"scenes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"release_date"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"as"}},{"kind":"Field","name":{"kind":"Name","value":"performer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}}]}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}}]} as unknown as DocumentNode; export const SearchTagsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"SearchTags"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"term"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}},"defaultValue":{"kind":"IntValue","value":"5"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","alias":{"kind":"Name","value":"exact"},"name":{"kind":"Name","value":"findTagOrAlias"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"term"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SearchTagFragment"}}]}},{"kind":"Field","alias":{"kind":"Name","value":"query"},"name":{"kind":"Name","value":"searchTag"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"term"},"value":{"kind":"Variable","name":{"kind":"Name","value":"term"}}},{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SearchTagFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SearchTagFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Tag"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}}]} as unknown as DocumentNode; export const SiteDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Site"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findSite"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"regex"}},{"kind":"Field","name":{"kind":"Name","value":"valid_types"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}}]}}]}}]} as unknown as DocumentNode; export const SitesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Sites"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"querySites"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"sites"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"regex"}},{"kind":"Field","name":{"kind":"Name","value":"valid_types"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"created"}},{"kind":"Field","name":{"kind":"Name","value":"updated"}}]}}]}}]}}]} as unknown as DocumentNode; export const StudioDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Studio"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findStudio"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StudioFragment"}},{"kind":"Field","name":{"kind":"Name","value":"sub_studios"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"count"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"StudioFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Studio"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}}]}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}}]} as unknown as DocumentNode; export const StudioPerformersDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"StudioPerformers"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"studioId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"gender"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"GenderFilterEnum"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"favorite"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"names"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},"defaultValue":{"kind":"IntValue","value":"1"}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"per_page"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},"defaultValue":{"kind":"IntValue","value":"25"}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"direction"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SortDirectionEnum"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sort"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PerformerSortEnum"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"queryPerformers"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"studio_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"studioId"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"gender"},"value":{"kind":"Variable","name":{"kind":"Name","value":"gender"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"is_favorite"},"value":{"kind":"Variable","name":{"kind":"Name","value":"favorite"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"names"},"value":{"kind":"Variable","name":{"kind":"Name","value":"names"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"per_page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"per_page"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"direction"},"value":{"kind":"Variable","name":{"kind":"Name","value":"direction"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"sort"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sort"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"count"}},{"kind":"Field","name":{"kind":"Name","value":"performers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"disambiguation"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"birth_date"}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"scenes"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"studio_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"studioId"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"release_date"}},{"kind":"Field","name":{"kind":"Name","value":"production_date"}},{"kind":"Field","name":{"kind":"Name","value":"studio"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}}]} as unknown as DocumentNode; export const StudiosDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Studios"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"StudioQueryInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"queryStudios"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"count"}},{"kind":"Field","name":{"kind":"Name","value":"studios"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"parent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"urls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"URLFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"is_favorite"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"URLFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"URL"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"site"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Image"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}}]} as unknown as DocumentNode; export const SubStudiosDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"SubStudios"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"StudioQueryInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findStudio"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"sub_studios"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"count"}},{"kind":"Field","name":{"kind":"Name","value":"studios"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]}}]} as unknown as DocumentNode; export const TagDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Tag"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"name"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findTag"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"name"}}},{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}},{"kind":"Field","name":{"kind":"Name","value":"deleted"}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"group"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}}]}}]}}]} as unknown as DocumentNode; export const TagsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Tags"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TagQueryInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"queryTags"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"count"}},{"kind":"Field","name":{"kind":"Name","value":"tags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"aliases"}}]}}]}}]}}]} as unknown as DocumentNode; export const UnreadNotificationCountDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"UnreadNotificationCount"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getUnreadNotificationCount"}}]}}]} as unknown as DocumentNode; export const UserDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"User"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"name"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findUser"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"username"},"value":{"kind":"Variable","name":{"kind":"Name","value":"name"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"roles"}},{"kind":"Field","name":{"kind":"Name","value":"api_key"}},{"kind":"Field","name":{"kind":"Name","value":"api_calls"}},{"kind":"Field","name":{"kind":"Name","value":"invited_by"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"invite_tokens"}},{"kind":"Field","name":{"kind":"Name","value":"invite_codes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"uses"}},{"kind":"Field","name":{"kind":"Name","value":"expires"}}]}},{"kind":"Field","name":{"kind":"Name","value":"vote_count"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"accept"}},{"kind":"Field","name":{"kind":"Name","value":"reject"}},{"kind":"Field","name":{"kind":"Name","value":"immediate_accept"}},{"kind":"Field","name":{"kind":"Name","value":"immediate_reject"}},{"kind":"Field","name":{"kind":"Name","value":"abstain"}}]}},{"kind":"Field","name":{"kind":"Name","value":"edit_count"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"immediate_accepted"}},{"kind":"Field","name":{"kind":"Name","value":"immediate_rejected"}},{"kind":"Field","name":{"kind":"Name","value":"accepted"}},{"kind":"Field","name":{"kind":"Name","value":"rejected"}},{"kind":"Field","name":{"kind":"Name","value":"failed"}},{"kind":"Field","name":{"kind":"Name","value":"canceled"}},{"kind":"Field","name":{"kind":"Name","value":"pending"}}]}},{"kind":"Field","name":{"kind":"Name","value":"notification_subscriptions"}}]}}]}}]} as unknown as DocumentNode; export const UsersDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Users"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UserQueryInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"queryUsers"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"count"}},{"kind":"Field","name":{"kind":"Name","value":"users"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"roles"}},{"kind":"Field","name":{"kind":"Name","value":"api_key"}},{"kind":"Field","name":{"kind":"Name","value":"api_calls"}},{"kind":"Field","name":{"kind":"Name","value":"invited_by"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"invite_tokens"}}]}}]}}]}}]} as unknown as DocumentNode; export const VersionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Version"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"version"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hash"}},{"kind":"Field","name":{"kind":"Name","value":"version"}},{"kind":"Field","name":{"kind":"Name","value":"build_time"}},{"kind":"Field","name":{"kind":"Name","value":"build_type"}}]}}]}}]} as unknown as DocumentNode; ================================================ FILE: frontend/src/hooks/index.ts ================================================ export { default as usePagination } from "./usePagination"; export { default as useEditFilter } from "./useEditFilter"; export { default as useAuth } from "./useAuth"; export { useToast } from "./useToast"; export { useQueryParams } from "./useQueryParams"; export { useCurrentUser } from "./useCurrentUser"; ================================================ FILE: frontend/src/hooks/toast.scss ================================================ .ToastContainer { position: fixed; bottom: 30px; right: 40px; z-index: 10; } .toast-header { float: right; background-color: transparent; padding: 0.75rem; } .toast.fade { transition: opacity 0.6s ease-in-out; } ================================================ FILE: frontend/src/hooks/useAuth.tsx ================================================ import { useMe } from "src/graphql"; import { getCachedUser, setCachedUser } from "src/utils"; import type { User } from "../context"; interface AuthResult { loading: boolean; user: User | undefined; } const useAuth = (): AuthResult => { const { loading, data } = useMe({ fetchPolicy: "network-only", }); setCachedUser(data?.me ?? undefined); return { loading, user: loading ? getCachedUser() : (data?.me ?? undefined) }; }; export default useAuth; ================================================ FILE: frontend/src/hooks/useBeforeUnload.ts ================================================ import { useEffect } from "react"; const unloadListener = (event: BeforeUnloadEvent) => { event.preventDefault(); event.returnValue = true; }; export const useBeforeUnload = () => { useEffect(() => { window.addEventListener("beforeunload", unloadListener); return () => window.removeEventListener("beforeunload", unloadListener); }, []); }; ================================================ FILE: frontend/src/hooks/useCurrentUser.tsx ================================================ import { useContext, useMemo, useCallback } from "react"; import { useConfig } from "src/graphql/queries"; import AuthContext from "src/context"; import { isAdmin as userIsAdmin, canEdit, canTagEdit, canVote, canModerate, } from "src/utils"; export const useCurrentUser = () => { const auth = useContext(AuthContext); const { data: config } = useConfig(); const requireTagRole = config?.getConfig.require_tag_role ?? false; const isAdmin = useMemo(() => userIsAdmin(auth.user), [auth.user]); const isEditor = useMemo(() => canEdit(auth.user), [auth.user]); const isVoter = useMemo(() => canVote(auth.user), [auth.user]); const isModerator = useMemo(() => canModerate(auth.user), [auth.user]); const isTagEditor = useMemo( () => (requireTagRole ? canTagEdit(auth.user) : canEdit(auth.user)), [auth.user, requireTagRole], ); const isSelf = useCallback( (user?: (typeof auth)["user"] | string | null) => { if (!auth.user?.id || !user) return false; if (typeof user === "string") return user === auth.user.id; return user?.id === auth.user.id; }, [auth.user], ); return { isAdmin, isSelf, isEditor, isTagEditor, isVoter, isModerator, isAuthenticated: auth.authenticated, user: auth.user, }; }; ================================================ FILE: frontend/src/hooks/useEditFilter.tsx ================================================ import { Button, Form, InputGroup } from "react-bootstrap"; import Select from "react-select"; import { faSortAmountUp, faSortAmountDown, } from "@fortawesome/free-solid-svg-icons"; import { OperationEnum, SortDirectionEnum, TargetTypeEnum, VoteStatusEnum, EditSortEnum, UserVotedFilterEnum, } from "src/graphql"; import { EditOperationTypes, EditTargetTypes, EditStatusTypes, UserVotedFilterTypes, } from "src/constants/enums"; import { Icon } from "src/components/fragments"; import { useQueryParams } from "src/hooks"; import { resolveEnum, ensureEnum } from "src/utils"; const sortOptions = [ { value: EditSortEnum.CREATED_AT, label: "Date created" }, { value: EditSortEnum.CLOSED_AT, label: "Date closed" }, { value: EditSortEnum.UPDATED_AT, label: "Date updated" }, ]; const botOptions = [ { label: "Include", value: "include", }, { label: "Exclude", value: "exclude", }, { label: "Only", value: "only", }, ]; interface EditFilterProps { sort?: EditSortEnum; direction?: SortDirectionEnum; type?: TargetTypeEnum; status?: VoteStatusEnum; operation?: OperationEnum; voted?: UserVotedFilterEnum; favorite?: boolean; bot?: boolean; userSubmitted?: boolean; showFavoriteOption?: boolean; showVotedFilter?: boolean; defaultVoteStatus?: VoteStatusEnum | "all"; defaultVoted?: UserVotedFilterEnum; defaultBot?: "include" | "exclude" | "only"; defaultUserSubmitted?: boolean; } const useEditFilter = ({ sort: fixedSort, direction: fixedDirection, type: fixedType, status: fixedStatus, operation: fixedOperation, voted: fixedVoted, favorite: fixedFavorite, bot: fixedBot, userSubmitted: fixedUserSubmitted, showFavoriteOption = true, showVotedFilter = true, defaultVoteStatus = "all", defaultVoted, defaultBot = "include", defaultUserSubmitted = true, }: EditFilterProps) => { const [params, setParams] = useQueryParams({ query: { name: "query", type: "string", default: "" }, sort: { name: "sort", type: "string", default: EditSortEnum.CREATED_AT }, direction: { name: "dir", type: "string", default: SortDirectionEnum.DESC }, operation: { name: "operation", type: "string", default: "" }, voted: { name: "voted", type: "string", default: defaultVoted, }, status: { name: "status", type: "string", default: defaultVoteStatus }, type: { name: "type", type: "string", default: "" }, favorite: { name: "favorite", type: "string", default: "false" }, bot: { name: "bot", type: "string", default: defaultBot }, user_submitted: { name: "user_submitted", type: "string", default: defaultUserSubmitted.toString(), }, }); const sort = ensureEnum(EditSortEnum, params.sort); const direction = ensureEnum(SortDirectionEnum, params.direction); const operation = resolveEnum(OperationEnum, params.operation); const voted = resolveEnum(UserVotedFilterEnum, params.voted); const status = resolveEnum(VoteStatusEnum, params.status, undefined); const type = resolveEnum(TargetTypeEnum, params.type); const favorite = params.favorite === "true"; const userSubmitted = params.user_submitted !== "false"; const selectedSort = fixedSort ?? sort; const selectedDirection = fixedDirection ?? direction; const selectedStatus = fixedStatus ?? status; const selectedType = fixedType ?? type; const selectedOperation = fixedOperation ?? operation; const selectedVoted = fixedVoted ?? voted; const selectedFavorite = fixedFavorite ?? favorite; const selectedBot = fixedBot ?? params.bot; const selectedUserSubmitted = fixedUserSubmitted ?? userSubmitted; const enumToOptions = (e: Record) => Object.keys(e).map((key) => ( )); const editFilter = (
Order setParams("sort", e.currentTarget.value)} defaultValue={selectedSort} > {sortOptions.map((s) => ( ))} Type setParams("type", e.currentTarget.value)} value={selectedType} disabled={!!fixedType} > {enumToOptions(EditTargetTypes)} Status setParams("status", e.currentTarget.value)} value={selectedStatus} disabled={!!fixedStatus} > {enumToOptions(EditStatusTypes)} Operation setParams("operation", e.currentTarget.value)} value={selectedOperation} disabled={!!fixedOperation} > {enumToOptions(EditOperationTypes)} {showVotedFilter && ( Voted setParams("voted", e.currentTarget.value)} value={selectedVoted} disabled={!!fixedVoted} > {enumToOptions(UserVotedFilterTypes)} )} {showFavoriteOption && ( Favorites setParams("favorite", e.currentTarget.checked.toString()) } /> )} Bot Edits o.value === gender)} placeholder="Gender" isClearable onChange={(e) => setParams("gender", e?.value ?? undefined)} classNamePrefix="react-select" className="performer-filter ms-2" /> setParams("sort", e.currentTarget.value.toLowerCase()) } defaultValue={sort ?? "name"} > {sortOptions.map((s) => ( ))} setParams("favorite", e.currentTarget.checked.toString()) } /> ); return ( <>

Performers

{isEditor && ( )}
{performers} ); }; export default PerformersComponent; ================================================ FILE: frontend/src/pages/performers/components/index.ts ================================================ export * from "./performerInfo"; export * from "./scenePairings"; ================================================ FILE: frontend/src/pages/performers/components/performerInfo.tsx ================================================ import type { FC } from "react"; import { Link } from "react-router-dom"; import { Button, Card, Col, Row, Table } from "react-bootstrap"; import { faCodeMerge } from "@fortawesome/free-solid-svg-icons"; import { GenderEnum, type PerformerFragment as Performer, usePerformer, } from "src/graphql"; import { useCurrentUser } from "src/hooks"; import { getCountryByISO, formatBodyModifications, formatMeasurements, formatCareer, createHref, } from "src/utils"; import { EthnicityTypes, HairColorTypes, EyeColorTypes, BreastTypes, } from "src/constants"; import { ROUTE_PERFORMER, ROUTE_PERFORMER_EDIT, ROUTE_PERFORMER_MERGE, ROUTE_PERFORMER_DELETE, } from "src/constants/route"; import { FavoriteStar, GenderIcon, PerformerName, Tooltip, Icon, } from "src/components/fragments"; import ImageCarousel from "src/components/imageCarousel"; const CLASSNAME = "PerformerInfo"; const CLASSNAME_ACTIONS = "PerformerInfo-actions"; interface Props { performer: Performer; } const Actions: FC = ({ performer }) => { const { isEditor } = useCurrentUser(); if (!isEditor || performer.deleted) return null; return (
Merge other performers into {performer.name} } >
); }; const PerformerAge = ({ age }: { age?: number | null }): React.ReactNode => { if (!age) return ""; return {`${age} years old`}; }; export const PerformerInfo: FC = ({ performer }) => { const { data: mergedInto } = usePerformer( { id: performer.merged_into_id ?? "" }, !performer.merged_into_id, ); return (

{mergedInto?.findPerformer && (
Merged into
)}
{performer.death_date && ( )} {performer.gender !== GenderEnum.MALE && performer.gender !== GenderEnum.TRANSGENDER_MALE && ( <> )}
Career {formatCareer( performer.career_start_year, performer.career_end_year, )}
Birthdate {performer.birth_date} {!performer.death_date && ( )}
Deathdate {performer.death_date}
Height
{(performer?.height ?? 0) > 0 && `${performer.height}cm`}
Measurements {formatMeasurements(performer)}
Breast type {performer.breast_type && BreastTypes[performer.breast_type]}
Nationality {getCountryByISO(performer.country)}
Ethnicity {performer.ethnicity && EthnicityTypes[performer.ethnicity]}
Eye color {performer.eye_color && EyeColorTypes[performer.eye_color]}
Hair color {performer.hair_color && HairColorTypes[performer.hair_color]}
Tattoos {formatBodyModifications(performer?.tattoos)}
Piercings {formatBodyModifications(performer?.piercings)}
Aliases {(performer.aliases || []).join(", ")}
{performer.urls.map((u) => ( ))}
); }; ================================================ FILE: frontend/src/pages/performers/components/scenePairings.tsx ================================================ import type { FC } from "react"; import { Button, Form, InputGroup, Row, Col } from "react-bootstrap"; import { debounce } from "lodash-es"; import Select from "react-select"; import { faSortAmountUp, faSortAmountDown, } from "@fortawesome/free-solid-svg-icons"; import { useScenePairings, GenderFilterEnum, PerformerSortEnum, SortDirectionEnum, } from "src/graphql"; import { Icon } from "src/components/fragments"; import PerformerCard from "src/components/performerCard"; import SceneCard from "src/components/sceneCard"; import { GenderFilterTypes } from "src/constants"; import { usePagination, useQueryParams } from "src/hooks"; import { ensureEnum, resolveEnum } from "src/utils"; import { List } from "src/components/list"; const PER_PAGE = 25; const genderOptions = Object.entries(GenderFilterEnum).map(([, value]) => ({ value, label: GenderFilterTypes[value], })); const sortOptions = [ { value: PerformerSortEnum.NAME, label: "Name" }, { value: PerformerSortEnum.BIRTHDATE, label: "Birthdate" }, { value: PerformerSortEnum.SCENE_COUNT, label: "Scene Count" }, { value: PerformerSortEnum.CAREER_START_YEAR, label: "Career Start" }, { value: PerformerSortEnum.DEBUT, label: "Scene Debut" }, { value: PerformerSortEnum.CREATED_AT, label: "Created At" }, ]; interface Props { id: string; } export const ScenePairings: FC = ({ id }) => { const [params, setParams] = useQueryParams({ query: { name: "query", type: "string", default: "" }, gender: { name: "gender", type: "string" }, direction: { name: "dir", type: "string", default: SortDirectionEnum.ASC }, sort: { name: "sort", type: "string", default: PerformerSortEnum.NAME }, favorite: { name: "favorite", type: "string", default: "false" }, scenes: { name: "scenes", type: "string", default: "false" }, }); const gender = resolveEnum(GenderFilterEnum, params.gender); const direction = ensureEnum(SortDirectionEnum, params.direction); const sort = ensureEnum(PerformerSortEnum, params.sort); const favorite = params.favorite === "true" || undefined; const fetchScenes = params.scenes === "true"; const { page, setPage } = usePagination(); const { data, loading } = useScenePairings({ performerId: id, names: params.query, gender, favorite, page, per_page: PER_PAGE, sort, direction, fetchScenes, }); const performers = data?.queryPerformers.performers; const debouncedHandler = debounce(setParams, 200); const filters = ( <> debouncedHandler("query", e.currentTarget.value)} placeholder="Filter performer name" defaultValue={params.query} className="w-auto" /> {isCreate && ( )} key && setActiveTab(key)} className="d-flex" > Name {errors?.name?.message} The primary name used by the performer. Disambiguation Required if the primary name is not unique. {changedName && ( setUpdateAliases((prev) => !prev)} label="Set unset performance aliases to old name" className="d-inline-block" /> )} Aliases ( )} /> Any names used by the performer different from the primary name. Gender {enumOptions(GENDER)} {errors?.gender?.message} Birthdate {errors?.birthdate?.message} Deathdate {errors?.deathdate?.message} If the precise date is unknown the day and/or month can be omitted. Eye Color {enumOptions(EYE)} {errors?.eye_color?.message} Hair Color {enumOptions(HAIR)} {errors?.hair_color?.message} Height {errors?.height?.message} Height in centimeters {fieldData.gender !== "MALE" && fieldData.gender !== "TRANSGENDER_MALE" && ( Breast type {enumOptions(BREAST)} {errors?.breastType?.message} )} {showBreastType && ( Band size {errors?.bandSize?.message} US Bra size number Cup size {errors?.cupSize?.message} US Bra size letter(s) Waist size {errors?.waistSize?.message} Waist circumference in inches Hip size {errors?.hipSize?.message} Hip circumference in inches )} Nationality ( ({ value: s as string, label: capitalize(s), }))} isMulti onChange={(values) => onChange(values.map((v) => v.value))} options={validSites.map((s) => ({ value: s, label: capitalize(s), }))} placeholder="Types this site can link to" /> )} /> {/* Workaround for typing error in react-hook-form */} {(errors.valid_types as unknown as { message: string })?.message} ); }; export default SiteForm; ================================================ FILE: frontend/src/pages/sites/siteForm/index.ts ================================================ export { default } from "./SiteForm"; ================================================ FILE: frontend/src/pages/studios/Studio.tsx ================================================ import type { FC } from "react"; import { Link, useLocation, useNavigate } from "react-router-dom"; import { Button, Tab, Tabs } from "react-bootstrap"; import { usePendingEditsCount, TargetTypeEnum, CriterionModifier, type StudioQuery, } from "src/graphql"; type Studio = NonNullable; import { useCurrentUser } from "src/hooks"; import { EditList, SceneList, URLList } from "src/components/list"; import { StudioPerformers, SubStudioPreview, SubStudioList, } from "./components"; import { getImage, createHref, studioHref, formatPendingEdits, getUrlBySite, } from "src/utils"; import { ROUTE_STUDIO_EDIT, ROUTE_STUDIO_DELETE } from "src/constants/route"; import { FavoriteStar } from "src/components/fragments"; const DEFAULT_TAB = "scenes"; interface Props { studio: Studio; } const StudioComponent: FC = ({ studio }) => { const { isEditor } = useCurrentUser(); const navigate = useNavigate(); const location = useLocation(); const activeTab = location.hash?.slice(1) || DEFAULT_TAB; const { data: editData } = usePendingEditsCount({ type: TargetTypeEnum.STUDIO, id: studio.id, }); const pendingEditCount = editData?.queryEdits.count; const studioImage = getImage(studio.images, "landscape"); const hasSubStudios = studio.sub_studios.count > 0; const setTab = (tab: string | null) => navigate({ hash: tab === DEFAULT_TAB ? "" : `#${tab}` }); const homeURL = getUrlBySite(studio.urls, "Home"); return ( <>

{studio.deleted ? ( {studio.name} ) : ( {studio.name} )}

{homeURL && (
{homeURL.site.name !== "Home" && ( {homeURL.site.name}: )} {homeURL.url}
)} {studio.parent && ( Part of{" "} {studio.parent.name} )} {studio.aliases.length > 0 && (
Aliases: {studio.aliases.join(", ")}
)}
{studioImage && (
Studio logo
)}
{isEditor && !studio.deleted && ( <> )}
{hasSubStudios && ( <>
Sub Studios
setTab("sub-studios")} /> )} {hasSubStudios && ( )} {hasSubStudios && ( )} ); }; export default StudioComponent; ================================================ FILE: frontend/src/pages/studios/StudioAdd.tsx ================================================ import { type FC, useState } from "react"; import { useNavigate } from "react-router-dom"; import { useStudioEdit, OperationEnum, type StudioEditDetailsInput, } from "src/graphql"; import { editHref } from "src/utils"; import StudioForm from "./studioForm"; const StudioAdd: FC = () => { const navigate = useNavigate(); const [submissionError, setSubmissionError] = useState(""); const [insertStudioEdit, { loading: saving }] = useStudioEdit({ onCompleted: (data) => { if (submissionError) setSubmissionError(""); if (data.studioEdit.id) navigate(editHref(data.studioEdit)); }, onError: (error) => setSubmissionError(error.message), }); const doInsert = (insertData: StudioEditDetailsInput, editNote: string) => { insertStudioEdit({ variables: { studioData: { edit: { operation: OperationEnum.CREATE, comment: editNote, }, details: insertData, }, }, }); }; return (

Add new studio


{submissionError && (
Error: {submissionError}
)}
); }; export default StudioAdd; ================================================ FILE: frontend/src/pages/studios/StudioDelete.tsx ================================================ import type { FC } from "react"; import { useNavigate } from "react-router-dom"; import { Button, Col, Form, Row } from "react-bootstrap"; import { useForm } from "react-hook-form"; import * as yup from "yup"; import { yupResolver } from "@hookform/resolvers/yup"; import { OperationEnum, useStudioEdit, type StudioFragment as Studio, } from "src/graphql"; import { EditNote } from "src/components/form"; import { editHref } from "src/utils"; const schema = yup.object({ id: yup.string().required(), note: yup.string().required("An edit note is required."), }); export type FormData = yup.Asserts; interface Props { studio: Studio; } const StudioDelete: FC = ({ studio }) => { const navigate = useNavigate(); const { register, handleSubmit, formState: { errors }, } = useForm({ resolver: yupResolver(schema), mode: "onBlur", }); const [deleteStudioEdit, { loading: deleting }] = useStudioEdit({ onCompleted: (data) => { if (data.studioEdit.id) navigate(editHref(data.studioEdit)); }, }); const handleDelete = (data: FormData) => deleteStudioEdit({ variables: { studioData: { edit: { operation: OperationEnum.DESTROY, id: data.id, comment: data.note, }, }, }, }); return (

Delete studio {studio.name}

); }; export default StudioDelete; ================================================ FILE: frontend/src/pages/studios/StudioEdit.tsx ================================================ import { type FC, useState } from "react"; import { useNavigate } from "react-router-dom"; import { useStudioEdit, type StudioEditDetailsInput, OperationEnum, type StudioQuery, } from "src/graphql"; type Studio = NonNullable; import { createHref } from "src/utils"; import { ROUTE_EDIT } from "src/constants"; import StudioForm from "./studioForm"; interface Props { studio: Studio; } const StudioEdit: FC = ({ studio }) => { const navigate = useNavigate(); const [submissionError, setSubmissionError] = useState(""); const [insertStudioEdit, { loading: saving }] = useStudioEdit({ onCompleted: (data) => { if (submissionError) setSubmissionError(""); if (data.studioEdit.id) navigate(createHref(ROUTE_EDIT, data.studioEdit)); }, onError: (error) => setSubmissionError(error.message), }); const doUpdate = (insertData: StudioEditDetailsInput, editNote: string) => { insertStudioEdit({ variables: { studioData: { edit: { id: studio.id, operation: OperationEnum.MODIFY, comment: editNote, }, details: insertData, }, }, }); }; return (

Edit {studio.name}


{submissionError && (
Error: {submissionError}
)}
); }; export default StudioEdit; ================================================ FILE: frontend/src/pages/studios/StudioEditUpdate.tsx ================================================ import { type FC, useState } from "react"; import { useNavigate } from "react-router-dom"; import { useStudioEditUpdate, type StudioEditDetailsInput, type EditUpdateQuery, } from "src/graphql"; import { createHref, isStudio, isStudioEdit } from "src/utils"; import StudioForm from "./studioForm"; type EditUpdate = NonNullable; import { ROUTE_EDIT } from "src/constants"; import Title from "src/components/title"; export const StudioEditUpdate: FC<{ edit: EditUpdate }> = ({ edit }) => { const navigate = useNavigate(); const [submissionError, setSubmissionError] = useState(""); const [updateStudioEdit, { loading: saving }] = useStudioEditUpdate({ onCompleted: (result) => { if (submissionError) setSubmissionError(""); if (result.studioEditUpdate.id) navigate(createHref(ROUTE_EDIT, result.studioEditUpdate)); }, onError: (error) => setSubmissionError(error.message), }); if ( !isStudioEdit(edit.details) || (edit.target !== null && !isStudio(edit.target)) ) return null; const doUpdate = (updateData: StudioEditDetailsInput, editNote: string) => { updateStudioEdit({ variables: { id: edit.id, studioData: { edit: { id: edit.target?.id, operation: edit.operation, comment: editNote, merge_source_ids: edit.merge_sources.map((s) => s.id), }, details: updateData, }, }, }); }; const studioName = edit?.target?.name ?? edit.details?.name; return (
<h3> Update studio edit for <i className="ms-2"> <b>{studioName}</b> </i> </h3> <hr /> <StudioForm studio={edit.target} initial={edit.details} callback={doUpdate} saving={saving} /> {submissionError && ( <div className="text-danger text-end col-9"> Error: {submissionError} </div> )} </div> ); }; ================================================ FILE: frontend/src/pages/studios/Studios.tsx ================================================ import type { FC } from "react"; import { Button, Card, Form } from "react-bootstrap"; import { Link } from "react-router-dom"; import { studioHref, createHref } from "src/utils"; import { ROUTE_STUDIO_ADD } from "src/constants/route"; import { debounce } from "lodash-es"; import { useStudios, SortDirectionEnum, StudioSortEnum } from "src/graphql"; import { useCurrentUser, usePagination, useQueryParams } from "src/hooks"; import { List } from "src/components/list"; import { FavoriteStar } from "src/components/fragments"; const PER_PAGE = 40; const StudiosComponent: FC = () => { const { isEditor } = useCurrentUser(); const [params, setParams] = useQueryParams({ query: { name: "query", type: "string", default: "" }, favorite: { name: "favorite", type: "string", default: "false" }, }); const favorite = params.favorite === "true" || undefined; const { page, setPage } = usePagination(); const { loading, data } = useStudios({ input: { names: params.query, is_favorite: favorite, page, per_page: PER_PAGE, direction: SortDirectionEnum.ASC, sort: StudioSortEnum.NAME, }, }); const studioList = data?.queryStudios.studios.map((s) => ( <li key={s.id} className={s.parent === null ? "fw-bold" : ""}> <Link to={studioHref(s)}>{s.name}</Link> {s.parent && ( <small className="bullet-separator text-muted"> <Link to={studioHref(s.parent)}>{s.parent.name}</Link> </small> )} <FavoriteStar entity={s} entityType="studio" className="ps-2" /> </li> )); const debouncedHandler = debounce(setParams, 200); const filters = ( <> <Form.Control id="studio-query" onChange={(e) => debouncedHandler("query", e.currentTarget.value)} placeholder="Filter studio name" defaultValue={params.query ?? ""} className="w-25 me-3" /> <Form.Group controlId="favorite"> <Form.Check className="mt-2" type="switch" label="Only favorites" defaultChecked={favorite} onChange={(e) => setParams("favorite", e.currentTarget.checked.toString()) } /> </Form.Group> </> ); return ( <> <div className="d-flex"> <h3 className="me-4">Studios</h3> {isEditor && ( <Link to={createHref(ROUTE_STUDIO_ADD)} className="ms-auto"> <Button className="me-auto">Create</Button> </Link> )} </div> <List entityName="studios" page={page} setPage={setPage} perPage={PER_PAGE} filters={filters} loading={loading} listCount={data?.queryStudios.count} > <Card> <Card.Body> <ul>{studioList}</ul> </Card.Body> </Card> </List> </> ); }; export default StudiosComponent; ================================================ FILE: frontend/src/pages/studios/components/index.ts ================================================ export * from "./studioPerformers"; export { SubStudioList } from "./subStudioList"; export { SubStudioPreview } from "./subStudioPreview"; ================================================ FILE: frontend/src/pages/studios/components/studioPerformers.tsx ================================================ import type { FC } from "react"; import { Button, Form, InputGroup, Row, Col } from "react-bootstrap"; import { debounce } from "lodash-es"; import Select from "react-select"; import { faSortAmountUp, faSortAmountDown, } from "@fortawesome/free-solid-svg-icons"; import { useStudioPerformers, GenderFilterEnum, PerformerSortEnum, SortDirectionEnum, } from "src/graphql"; import { Icon } from "src/components/fragments"; import PerformerCard from "src/components/performerCard"; import SceneCard from "src/components/sceneCard"; import { GenderFilterTypes } from "src/constants"; import { usePagination, useQueryParams } from "src/hooks"; import { ensureEnum, resolveEnum } from "src/utils"; import { List } from "src/components/list"; const PER_PAGE = 25; const genderOptions = Object.entries(GenderFilterEnum).map(([, value]) => ({ value, label: GenderFilterTypes[value], })); const sortOptions = [ { value: PerformerSortEnum.LAST_SCENE, label: "Latest Scene" }, { value: PerformerSortEnum.DEBUT, label: "First Scene" }, { value: PerformerSortEnum.NAME, label: "Name" }, { value: PerformerSortEnum.SCENE_COUNT, label: "Scene Count" }, ]; interface Props { id: string; } export const StudioPerformers: FC<Props> = ({ id }) => { const [params, setParams] = useQueryParams({ query: { name: "query", type: "string", default: "" }, gender: { name: "gender", type: "string" }, direction: { name: "dir", type: "string", default: SortDirectionEnum.DESC }, sort: { name: "sort", type: "string", default: PerformerSortEnum.LAST_SCENE, }, favorite: { name: "favorite", type: "string", default: "false" }, }); const gender = resolveEnum(GenderFilterEnum, params.gender); const direction = ensureEnum(SortDirectionEnum, params.direction); const sort = ensureEnum(PerformerSortEnum, params.sort); const favorite = params.favorite === "true" || undefined; const names = params.query || undefined; const { page, setPage } = usePagination(); const { data, loading } = useStudioPerformers({ studioId: id, gender, favorite, names, page, per_page: PER_PAGE, sort, direction, }); const performers = data?.queryPerformers.performers; const debouncedHandler = debounce(setParams, 200); const filters = ( <> <Form.Control id="performer-name" onChange={(e) => debouncedHandler("query", e.currentTarget.value)} placeholder="Filter performer name" defaultValue={params.query} className="w-auto" /> <Select id="performer-gender" options={genderOptions} defaultValue={genderOptions.find((o) => o.value === gender)} placeholder="Gender" isClearable onChange={(e) => setParams("gender", e?.value ?? undefined)} classNamePrefix="react-select" className="performer-filter ms-2" /> <InputGroup className="performer-sort ms-2 me-3"> <Form.Select onChange={(e) => setParams("sort", e.currentTarget.value.toLowerCase()) } defaultValue={sort ?? "name"} > {sortOptions.map((s) => ( <option value={s.value} key={s.value}> {s.label} </option> ))} </Form.Select> <Button variant="secondary" onClick={() => setParams( "direction", direction === SortDirectionEnum.DESC ? SortDirectionEnum.ASC : undefined, ) } > <Icon icon={ direction === SortDirectionEnum.DESC ? faSortAmountDown : faSortAmountUp } /> </Button> </InputGroup> <Form.Group controlId="favorite"> <Form.Check className="mt-2" type="switch" label="Only favorites" defaultChecked={favorite} onChange={(e) => setParams("favorite", e.currentTarget.checked.toString()) } /> </Form.Group> </> ); return ( <List entityName="Scene Pairings" page={page} filters={filters} setPage={setPage} perPage={PER_PAGE} loading={loading} listCount={data?.queryPerformers?.count} > {performers?.map((p, i) => ( <Row key={p.id}> <Col xs={3} key={p.id}> <PerformerCard performer={p} /> </Col> <Col xs={9}> <Row> {p.scenes.map((s) => ( <Col xs={4} key={s.id}> <SceneCard scene={s} /> </Col> ))} </Row> </Col> {i < performers.length - 1 && <hr />} </Row> ))} </List> ); }; ================================================ FILE: frontend/src/pages/studios/components/subStudioList.tsx ================================================ import { type FC, useState, useMemo } from "react"; import { Card, Form } from "react-bootstrap"; import { Link } from "react-router-dom"; import { debounce } from "lodash-es"; import { useSubStudios, SortDirectionEnum, StudioSortEnum } from "src/graphql"; import { usePagination } from "src/hooks"; import { List } from "src/components/list"; import { studioHref } from "src/utils"; const PER_PAGE = 25; interface Props { id: string; } export const SubStudioList: FC<Props> = ({ id }) => { const [filter, setFilter] = useState(""); const names = filter || undefined; const { page, setPage } = usePagination(); const { data, loading } = useSubStudios({ id, input: { page, per_page: PER_PAGE, sort: StudioSortEnum.NAME, direction: SortDirectionEnum.ASC, names, }, }); const studios = data?.findStudio?.sub_studios.studios; const showLoading = loading && !studios; const debouncedSetFilter = useMemo(() => debounce(setFilter, 200), []); const filters = ( <Form.Control id="sub-studio-name" onChange={(e) => debouncedSetFilter(e.currentTarget.value)} placeholder="Filter by name" className="w-auto" /> ); return ( <List entityName="sub-studios" page={page} filters={filters} setPage={setPage} perPage={PER_PAGE} loading={showLoading} listCount={data?.findStudio?.sub_studios.count} > <Card> <Card.Body> <ul> {studios?.map((s) => ( <li key={s.id}> <Link to={studioHref(s)}>{s.name}</Link> </li> ))} </ul> </Card.Body> </Card> </List> ); }; ================================================ FILE: frontend/src/pages/studios/components/subStudioPreview.tsx ================================================ import type { FC } from "react"; import { Link } from "react-router-dom"; import { useSubStudios, SortDirectionEnum, StudioSortEnum } from "src/graphql"; import { LoadingIndicator } from "src/components/fragments"; import { studioHref } from "src/utils"; const PREVIEW_COUNT = 25; interface Props { id: string; onViewAll: () => void; } export const SubStudioPreview: FC<Props> = ({ id, onViewAll }) => { const { data, loading } = useSubStudios({ id, input: { page: 1, per_page: PREVIEW_COUNT, sort: StudioSortEnum.NAME, direction: SortDirectionEnum.ASC, }, }); const studios = data?.findStudio?.sub_studios.studios; const count = data?.findStudio?.sub_studios.count ?? 0; const hasMore = count > PREVIEW_COUNT; if (loading) return <LoadingIndicator message="Loading sub-studios..." />; return ( <div className="sub-studio-list"> <ul> {studios?.map((s) => ( <li key={s.id}> <Link to={studioHref(s)}>{s.name}</Link> </li> ))} {hasMore && ( <li key="view-all" style={{ listStyle: "none", marginLeft: "-1rem" }}> <button type="button" className="btn btn-link p-0" onClick={onViewAll} > View all {count} sub-studios </button> </li> )} </ul> </div> ); }; ================================================ FILE: frontend/src/pages/studios/index.tsx ================================================ import type { FC } from "react"; import { Route, Routes, useParams } from "react-router-dom"; import { ErrorMessage, LoadingIndicator } from "src/components/fragments"; import { useStudio } from "src/graphql"; import Title from "src/components/title"; import Studio from "./Studio"; import Studios from "./Studios"; import StudioEdit from "./StudioEdit"; import StudioAdd from "./StudioAdd"; import StudioDelete from "./StudioDelete"; const StudioLoader: FC = () => { const { id } = useParams(); const { loading, data } = useStudio({ id: id ?? "" }, !id); if (loading) return <LoadingIndicator message="Loading studio..." />; if (!id) return <ErrorMessage error="Studio ID is missing" />; const studio = data?.findStudio; if (!studio) return <ErrorMessage error="Studio not found." />; return ( <Routes> <Route path="/delete" element={ <> <Title page={`Delete "${studio.name}"`} /> <StudioDelete studio={studio} /> </> } /> <Route path="/edit" element={ <> <Title page={`Edit "${studio.name}"`} /> <StudioEdit studio={studio} /> </> } /> <Route path="/" element={ <> <Title page={studio.name} /> <Studio studio={studio} /> </> } /> </Routes> ); }; const StudioRoutes: FC = () => ( <Routes> <Route path="/add" element={ <> <Title page="Add Studio" /> <StudioAdd /> </> } /> <Route path="/" element={ <> <Title page="Studios" /> <Studios /> </> } /> <Route path="/:id/*" element={<StudioLoader />} /> </Routes> ); export default StudioRoutes; ================================================ FILE: frontend/src/pages/studios/studioForm/StudioForm.tsx ================================================ import { type FC, useMemo, useState } from "react"; import { Row, Col, Form, Tab, Tabs } from "react-bootstrap"; import { Controller, useForm } from "react-hook-form"; import { yupResolver } from "@hookform/resolvers/yup"; import { useLens } from "@hookform/lenses"; import cx from "classnames"; import { Link } from "react-router-dom"; import { faExclamationTriangle } from "@fortawesome/free-solid-svg-icons"; import { type StudioEditDetailsInput, ValidSiteTypeEnum, type StudioFragment as Studio, type ImageFragment, } from "src/graphql"; import { Icon } from "src/components/fragments"; import StudioSelect from "src/components/studioSelect"; import EditImages from "src/components/editImages"; import { EditNote, NavButtons, SubmitButtons } from "src/components/form"; import URLInput from "src/components/urlInput"; import { renderStudioDetails } from "src/components/editCard/ModifyEdit"; import { StudioSchema, type StudioFormData } from "./schema"; import type { InitialStudio } from "./types"; import DiffStudio from "./diff"; import { useBeforeUnload } from "src/hooks/useBeforeUnload"; import MultiSelect from "src/components/multiSelect"; interface StudioProps { studio?: Studio | null; callback: (data: StudioEditDetailsInput, editNote: string) => void; showNetworkSelect?: boolean; initial?: InitialStudio; saving: boolean; } const StudioForm: FC<StudioProps> = ({ studio, callback, showNetworkSelect = true, initial, saving, }) => { useBeforeUnload(); const initialAliases = initial?.aliases ?? studio?.aliases ?? []; const { register, control, handleSubmit, watch, formState: { errors }, } = useForm({ resolver: yupResolver(StudioSchema), defaultValues: { name: initial?.name ?? studio?.name, aliases: initialAliases, images: initial?.images ?? studio?.images ?? [], urls: initial?.urls ?? studio?.urls ?? [], parent: initial?.parent ?? studio?.parent, }, }); const lens = useLens({ control }); const [file, setFile] = useState<File | undefined>(); const fieldData = watch(); const [oldStudioChanges, newStudioChanges] = useMemo( () => DiffStudio( StudioSchema.cast(fieldData, { assert: "ignore-optionality", }) as StudioFormData, studio, ), [fieldData, studio], ); const [activeTab, setActiveTab] = useState("details"); const onSubmit = (data: StudioFormData) => { const callbackData: StudioEditDetailsInput = { name: data.name, aliases: data.aliases ?? [], urls: data.urls?.map((u) => ({ url: u.url, site_id: u.site.id, })), image_ids: data.images.map((i) => i.id), parent_id: data.parent?.id ?? null, }; callback(callbackData, data.note); }; const metadataErrors = [ { error: errors.name?.message, tab: "details" }, { error: errors.urls?.find?.((u) => u?.url?.message)?.url?.message, tab: "links", }, ].filter((e) => e.error) as { error: string; tab: string }[]; return ( <Form className="StudioForm" onSubmit={handleSubmit(onSubmit)}> <Tabs activeKey={activeTab} onSelect={(key) => key && setActiveTab(key)} className="d-flex" > <Tab eventKey="details" title="Details" className="col-xl-6"> <Form.Group controlId="name" className="mb-3"> <Form.Label>Name</Form.Label> <Form.Control className={cx({ "is-invalid": errors.name })} placeholder="Name" {...register("name")} /> <Form.Control.Feedback type="invalid"> {errors?.name?.message} </Form.Control.Feedback> </Form.Group> <Form.Group controlId="aliases" className="mb-3"> <Form.Label>Aliases</Form.Label> <Controller name="aliases" control={control} render={({ field: { onChange } }) => ( <MultiSelect initialValues={initialAliases} onChange={onChange} placeholder="Enter name..." /> )} /> <Form.Control.Feedback type="invalid"> {errors?.aliases?.message} </Form.Control.Feedback> </Form.Group> {showNetworkSelect && ( <Form.Group controlId="network" className="mb-3"> <Form.Label>Network</Form.Label> <Controller name="parent" control={control} render={({ field: { onChange, value } }) => ( <StudioSelect excludeStudio={studio?.id} initialStudio={value} onChange={onChange} isClearable networkSelect /> )} /> </Form.Group> )} <NavButtons onNext={() => setActiveTab("links")} /> </Tab> <Tab eventKey="links" title="Links" className="col-xl-9"> <Form.Group className="mb-3"> <Form.Label>Links</Form.Label> <URLInput lens={lens.focus("urls").defined()} type={ValidSiteTypeEnum.STUDIO} errors={errors.urls} /> </Form.Group> <NavButtons onNext={() => setActiveTab("images")} /> </Tab> <Tab eventKey="images" title="Images" className="col-xl-6"> <EditImages lens={lens.focus("images").cast<ImageFragment[]>()} maxImages={1} file={file} setFile={(f) => setFile(f)} allowLossless /> <NavButtons onNext={() => setActiveTab("confirm")} disabled={!!file} /> <div className="d-flex"> {/* dummy element for feedback */} <div className="ms-auto"> <span className={file ? "is-invalid" : ""} /> <Form.Control.Feedback type="invalid"> Upload or remove image to continue. </Form.Control.Feedback> </div> </div> </Tab> <Tab eventKey="confirm" title="Confirm" className="mt-3 col-xl-9"> {renderStudioDetails(newStudioChanges, oldStudioChanges, !!studio)} <Row className="my-4"> <Col md={{ span: 8, offset: 4 }}> <EditNote register={register} error={errors.note} /> </Col> </Row> {metadataErrors.length > 0 && ( <div className="text-end my-4"> <h6> <Icon icon={faExclamationTriangle} color="red" /> <span className="ms-1">Errors</span> </h6> <div className="d-flex flex-column text-danger"> {metadataErrors.map(({ error, tab }) => ( <Link to="#" key={error} onClick={() => setActiveTab(tab)}> {error} </Link> ))} </div> </div> )} <SubmitButtons disabled={!!file || saving} /> </Tab> </Tabs> </Form> ); }; export default StudioForm; ================================================ FILE: frontend/src/pages/studios/studioForm/diff.ts ================================================ import type { OldStudioDetails, StudioDetails, } from "src/components/editCard/ModifyEdit"; import type { StudioFragment } from "src/graphql"; import type { StudioFormData } from "./schema"; import { diffValue, diffImages, diffURLs, diffArray } from "src/utils"; const selectStudioDetails = ( data: StudioFormData, original: StudioFragment | null | undefined, ): [Required<OldStudioDetails>, Required<StudioDetails>] => { const [addedImages, removedImages] = diffImages( data.images, original?.images ?? [], ); const [addedUrls, removedUrls] = diffURLs(data.urls, original?.urls ?? []); const [addedAliases, removedAliases] = diffArray( data?.aliases, original?.aliases ?? [], (a) => a, ); return [ { name: diffValue(original?.name, data.name), parent: original?.parent?.id !== data.parent?.id && original?.parent?.id && original?.parent.name ? { id: original.parent.id, name: original.parent.name, } : null, }, { name: diffValue(data.name, original?.name), parent: data.parent?.id !== original?.parent?.id && data.parent?.id && data.parent?.name ? { id: data.parent.id, name: data.parent.name, } : null, added_urls: addedUrls, removed_urls: removedUrls, added_images: addedImages, removed_images: removedImages, added_aliases: addedAliases, removed_aliases: removedAliases, }, ]; }; export default selectStudioDetails; ================================================ FILE: frontend/src/pages/studios/studioForm/index.ts ================================================ import StudioForm from "./StudioForm"; export default StudioForm; ================================================ FILE: frontend/src/pages/studios/studioForm/schema.ts ================================================ import * as yup from "yup"; export const StudioSchema = yup.object({ name: yup.string().trim().required("Name is required"), aliases: yup.array().of(yup.string().trim().ensure()).ensure().default([]), urls: yup .array() .of( yup.object({ url: yup.string().url("Invalid URL").required(), site: yup .object({ id: yup.string().required(), name: yup.string().required(), icon: yup.string().required(), }) .required(), }), ) .ensure(), images: yup .array() .of( yup.object({ id: yup.string().required(), url: yup.string().required(), width: yup.number().required(), height: yup.number().required(), }), ) .required(), parent: yup .object({ id: yup.string().required(), name: yup.string().required(), }) .nullable() .default(null), note: yup.string().required("Edit note is required"), }); export type StudioFormData = yup.Asserts<typeof StudioSchema>; ================================================ FILE: frontend/src/pages/studios/studioForm/types.ts ================================================ export type InitialStudio = { name?: string | null; aliases?: string[]; parent?: { id: string; name: string; } | null; images?: { id: string; height: number; width: number; url: string; }[]; urls?: { url: string; site: { id: string; name: string; }; }[]; }; ================================================ FILE: frontend/src/pages/studios/styles.scss ================================================ .studio-photo { flex-grow: 1; margin-right: 1rem; max-height: 100px; text-align: right; img { max-height: 100%; max-width: 32rem; } } .sub-studio-list { margin-bottom: 1rem; max-height: 15rem; overflow-y: auto; ul { column-count: 3; margin-bottom: 0; } } .StudioForm { .EditImages { &-images, &-input { flex: unset; width: unset; } &-drop { height: 200px; padding: 1rem; } } } ================================================ FILE: frontend/src/pages/tags/Tag.tsx ================================================ import type { FC } from "react"; import { Link, useLocation, useNavigate } from "react-router-dom"; import { Button, Tab, Tabs } from "react-bootstrap"; import { usePendingEditsCount, CriterionModifier, TargetTypeEnum, type TagFragment as Tag, } from "src/graphql"; import { Tooltip } from "src/components/fragments"; import { EditList, SceneList } from "src/components/list"; import { createHref, tagHref, formatPendingEdits } from "src/utils"; import { ROUTE_TAG_EDIT, ROUTE_TAG_MERGE, ROUTE_TAG_DELETE, ROUTE_CATEGORY, } from "src/constants/route"; import { useCurrentUser } from "src/hooks"; const DEFAULT_TAB = "scenes"; interface Props { tag: Tag; } const TagComponent: FC<Props> = ({ tag }) => { const { isTagEditor } = useCurrentUser(); const navigate = useNavigate(); const location = useLocation(); const activeTab = location.hash?.slice(1) || DEFAULT_TAB; const { data: editData } = usePendingEditsCount({ type: TargetTypeEnum.TAG, id: tag.id, }); const pendingEditCount = editData?.queryEdits.count; const setTab = (tab: string | null) => navigate({ hash: tab === DEFAULT_TAB ? "" : `#${tab}` }); return ( <> <div className="d-flex"> <h3> <span className="me-2">Tag:</span> {tag.deleted ? <del>{tag.name}</del> : <em>{tag.name}</em>} </h3> {isTagEditor && !tag.deleted && ( <div className="ms-auto"> <Link to={tagHref(tag, ROUTE_TAG_EDIT)} className="ms-2"> <Button>Edit</Button> </Link> <Link to={tagHref(tag, ROUTE_TAG_MERGE)} className="ms-2"> <Tooltip text={ <> Merge other tags into <b>{tag.name}</b> </> } > <Button>Merge</Button> </Tooltip> </Link> <Link to={createHref(ROUTE_TAG_DELETE, tag)} className="ms-2"> <Button variant="danger">Delete</Button> </Link> </div> )} </div> {tag.description && ( <div className="d-flex"> <b className="me-2">Description:</b> <span>{tag.description}</span> </div> )} {tag.category && ( <div className="d-flex"> <b className="me-2">Category:</b> <Link to={createHref(ROUTE_CATEGORY, tag.category)}> {tag.category.name} </Link> </div> )} {tag.aliases.length > 0 && ( <div className="d-flex"> <b className="me-2">Aliases:</b> <span>{tag.aliases.join(", ")}</span> </div> )} <hr className="my-2" /> <Tabs activeKey={activeTab} id="tag-tabs" mountOnEnter onSelect={setTab}> <Tab eventKey="scenes" title="Scenes"> <SceneList tagsFilter={{ value: [tag.id], modifier: CriterionModifier.INCLUDES, }} favoriteFilter="all" /> </Tab> <Tab eventKey="edits" title={`Edits${formatPendingEdits(pendingEditCount)}`} tabClassName={pendingEditCount ? "PendingEditTab" : ""} > <EditList type={TargetTypeEnum.TAG} id={tag.id} /> </Tab> </Tabs> </> ); }; export default TagComponent; ================================================ FILE: frontend/src/pages/tags/TagAdd.tsx ================================================ import { type FC, useState } from "react"; import { useNavigate } from "react-router-dom"; import { useTagEdit, OperationEnum, type TagEditDetailsInput, } from "src/graphql"; import { editHref } from "src/utils"; import TagForm from "./tagForm"; const TagAddComponent: FC = () => { const navigate = useNavigate(); const [submissionError, setSubmissionError] = useState(""); const [insertTagEdit, { loading: saving }] = useTagEdit({ onCompleted: (data) => { if (submissionError) setSubmissionError(""); if (data.tagEdit.id) navigate(editHref(data.tagEdit)); }, onError: (error) => setSubmissionError(error.message), }); const doInsert = (insertData: TagEditDetailsInput, editNote: string) => { insertTagEdit({ variables: { tagData: { edit: { operation: OperationEnum.CREATE, comment: editNote, }, details: insertData, }, }, }); }; return ( <div> <h3>Add new tag</h3> <hr /> <TagForm callback={doInsert} saving={saving} /> {submissionError && ( <div className="text-danger text-end col-9"> Error: {submissionError} </div> )} </div> ); }; export default TagAddComponent; ================================================ FILE: frontend/src/pages/tags/TagDelete.tsx ================================================ import type { FC } from "react"; import { useNavigate } from "react-router-dom"; import { Button, Col, Form, Row } from "react-bootstrap"; import { useForm } from "react-hook-form"; import * as yup from "yup"; import { yupResolver } from "@hookform/resolvers/yup"; import { useTagEdit, OperationEnum, type TagFragment as Tag, } from "src/graphql"; import { EditNote } from "src/components/form"; import { editHref } from "src/utils"; const schema = yup.object({ id: yup.string().required(), note: yup.string().required("An edit note is required."), }); export type FormData = yup.Asserts<typeof schema>; interface Props { tag: Tag; } const TagDelete: FC<Props> = ({ tag }) => { const navigate = useNavigate(); const { register, handleSubmit, formState: { errors }, } = useForm<FormData>({ resolver: yupResolver(schema), mode: "onBlur", }); const [deleteTagEdit, { loading: deleting }] = useTagEdit({ onCompleted: (data) => { if (data.tagEdit.id) navigate(editHref(data.tagEdit)); }, }); const handleDelete = (data: FormData) => deleteTagEdit({ variables: { tagData: { edit: { operation: OperationEnum.DESTROY, id: data.id, comment: data.note, }, }, }, }); return ( <Form className="TagDeleteForm" onSubmit={handleSubmit(handleDelete)}> <Row> <h4> Delete tag <em>{tag.name}</em> </h4> </Row> <Form.Control type="hidden" value={tag.id} {...register("id")} /> <Row className="my-4"> <Col md={6}> <EditNote register={register} error={errors.note} /> <div className="d-flex mt-2"> <Button variant="danger" className="ms-auto me-2" onClick={() => navigate(-1)} > Cancel </Button> <Button type="submit" disabled className="d-none" aria-hidden="true" /> <Button type="submit" disabled={deleting}> Submit Edit </Button> </div> </Col> </Row> </Form> ); }; export default TagDelete; ================================================ FILE: frontend/src/pages/tags/TagEdit.tsx ================================================ import { type FC, useState } from "react"; import { useNavigate } from "react-router-dom"; import { useTagEdit, OperationEnum, type TagEditDetailsInput, type TagFragment as Tag, } from "src/graphql"; import { ROUTE_EDIT } from "src/constants/route"; import { createHref } from "src/utils/route"; import TagForm from "./tagForm"; interface Props { tag: Tag; } const TagEdit: FC<Props> = ({ tag }) => { const navigate = useNavigate(); const [submissionError, setSubmissionError] = useState(""); const [insertTagEdit, { loading: saving }] = useTagEdit({ onCompleted: (data) => { if (submissionError) setSubmissionError(""); if (data.tagEdit.id) navigate(createHref(ROUTE_EDIT, data.tagEdit)); }, onError: (error) => setSubmissionError(error.message), }); const doUpdate = (insertData: TagEditDetailsInput, editNote: string) => { insertTagEdit({ variables: { tagData: { edit: { id: tag.id, operation: OperationEnum.MODIFY, comment: editNote, }, details: insertData, }, }, }); }; return ( <div> <h3>Edit tag</h3> <hr /> <TagForm tag={tag} callback={doUpdate} saving={saving} /> {submissionError && ( <div className="text-danger col-9">Error: {submissionError}</div> )} </div> ); }; export default TagEdit; ================================================ FILE: frontend/src/pages/tags/TagEditUpdate.tsx ================================================ import { type FC, useState } from "react"; import { useNavigate } from "react-router-dom"; import { useTagEditUpdate, type TagEditDetailsInput, type EditUpdateQuery, } from "src/graphql"; import { createHref, isTag, isTagEdit } from "src/utils"; import TagForm from "./tagForm"; type EditUpdate = NonNullable<EditUpdateQuery["findEdit"]>; import { ROUTE_EDIT } from "src/constants"; import Title from "src/components/title"; export const TagEditUpdate: FC<{ edit: EditUpdate }> = ({ edit }) => { const navigate = useNavigate(); const [submissionError, setSubmissionError] = useState(""); const [updateTagEdit, { loading: saving }] = useTagEditUpdate({ onCompleted: (result) => { if (submissionError) setSubmissionError(""); if (result.tagEditUpdate.id) navigate(createHref(ROUTE_EDIT, result.tagEditUpdate)); }, onError: (error) => setSubmissionError(error.message), }); if (!isTagEdit(edit.details) || (edit.target && !isTag(edit.target))) return null; const doUpdate = (updateData: TagEditDetailsInput, editNote: string) => { updateTagEdit({ variables: { id: edit.id, tagData: { edit: { id: edit.target?.id, operation: edit.operation, comment: editNote, merge_source_ids: edit.merge_sources.map((s) => s.id), }, details: updateData, }, }, }); }; const tagName = edit.target?.name ?? edit.details.name; return ( <div> <Title page={`Update tag edit for "${tagName}"`} /> <h3> Update tag edit for <i className="ms-2"> <b>{tagName}</b> </i> </h3> <hr /> <TagForm tag={edit.target} initial={edit.details} callback={doUpdate} saving={saving} /> {submissionError && ( <div className="text-danger text-end col-9"> Error: {submissionError} </div> )} </div> ); }; ================================================ FILE: frontend/src/pages/tags/TagMerge.tsx ================================================ import { type FC, useState } from "react"; import { useNavigate } from "react-router-dom"; import { Col, Row } from "react-bootstrap"; import { flatMap, uniq } from "lodash-es"; import { useTagEdit, OperationEnum, type TagEditDetailsInput, type TagFragment as Tag, } from "src/graphql"; import TagSelect from "src/components/tagSelect"; import { editHref } from "src/utils"; import TagForm from "./tagForm"; interface Props { tag: Tag; } type TagSlim = { id: string; name: string; aliases: string[]; }; const TagMerge: FC<Props> = ({ tag }) => { const navigate = useNavigate(); const [submissionError, setSubmissionError] = useState(""); const [mergeSources, setMergeSources] = useState<TagSlim[]>([]); const [insertTagEdit, { loading: saving }] = useTagEdit({ onCompleted: (data) => { if (submissionError) setSubmissionError(""); if (data.tagEdit.id) navigate(editHref(data.tagEdit)); }, onError: (error) => setSubmissionError(error.message), }); const doUpdate = (insertData: TagEditDetailsInput, editNote: string) => { insertTagEdit({ variables: { tagData: { edit: { id: tag.id, operation: OperationEnum.MERGE, merge_source_ids: mergeSources.map((t) => t.id), comment: editNote, }, details: insertData, }, }, }); }; const aliases = uniq([ ...tag.aliases, ...mergeSources.map((t) => t.name), ...flatMap(mergeSources, (t) => t.aliases), ]); return ( <div> <h3> Merge tags into <em>{tag.name}</em> </h3> <hr /> <Row className="g-0"> <Col xs={6}> <TagSelect tags={[]} onChange={(tags) => setMergeSources(tags)} message="Select tags to merge:" excludeTags={[tag.id, ...mergeSources.map((t) => t.id)]} /> </Col> </Row> <hr className="my-4" /> <h5> Modify <em>{tag.name}</em> </h5> <Row className="g-0"> {submissionError && ( <div className="text-danger mb-2">Error: {submissionError}</div> )} <TagForm tag={tag} callback={doUpdate} saving={saving} initial={{ aliases }} /> </Row> </div> ); }; export default TagMerge; ================================================ FILE: frontend/src/pages/tags/Tags.tsx ================================================ import type { FC } from "react"; import { Button } from "react-bootstrap"; import { Link } from "react-router-dom"; import { TagList } from "src/components/list"; import { createHref } from "src/utils"; import { ROUTE_TAG_ADD } from "src/constants/route"; import { useCurrentUser } from "src/hooks"; const Tags: FC = () => { const { isTagEditor } = useCurrentUser(); return ( <> <div className="d-flex"> <h3>Tags</h3> {isTagEditor && ( <Link to={createHref(ROUTE_TAG_ADD)} className="ms-auto"> <Button className="ms-auto">Create</Button> </Link> )} </div> <TagList tagFilter={{}} showCategoryLink /> </> ); }; export default Tags; ================================================ FILE: frontend/src/pages/tags/index.tsx ================================================ import type { FC } from "react"; import { Route, Routes, useParams } from "react-router-dom"; import { useTag } from "src/graphql"; import Title from "src/components/title"; import { ErrorMessage, LoadingIndicator } from "src/components/fragments"; import Tag from "./Tag"; import Tags from "./Tags"; import TagAdd from "./TagAdd"; import TagEdit from "./TagEdit"; import TagMerge from "./TagMerge"; import TagDelete from "./TagDelete"; const TagLoader: FC = () => { const { id } = useParams<{ id: string }>(); const { data, loading } = useTag({ id }); if (loading) return <LoadingIndicator message="Loading tag..." />; if (!id) return <ErrorMessage error="Tag ID is missing" />; const tag = data?.findTag; if (!tag) return <ErrorMessage error="Tag not found." />; return ( <Routes> <Route path="/merge" element={ <> <Title page={`Merge Tag "${tag.name}"`} /> <TagMerge tag={tag} /> </> } /> <Route path="/delete" element={ <> <Title page={`Delete Tag "${tag.name}"`} /> <TagDelete tag={tag} /> </> } /> <Route path="/edit" element={ <> <Title page={`Edit Tag "${tag.name}"`} /> <TagEdit tag={tag} /> </> } /> <Route path="/" element={ <> <Title page={`Tag "${tag.name}"`} /> <Tag tag={tag} /> </> } /> </Routes> ); }; const TagRoutes: FC = () => ( <Routes> <Route path="/" element={ <> <Title page="Tags" /> <Tags /> </> } /> <Route path="/add" element={ <> <Title page="Add Tag" /> <TagAdd /> </> } /> <Route path="/:id/*" element={<TagLoader />} /> </Routes> ); export default TagRoutes; ================================================ FILE: frontend/src/pages/tags/tagForm/TagForm.tsx ================================================ import type { FC } from "react"; import { useForm, Controller, type FieldError } from "react-hook-form"; import { yupResolver } from "@hookform/resolvers/yup"; import cx from "classnames"; import { Button, Form } from "react-bootstrap"; import Select from "react-select"; import { groupBy, sortBy } from "lodash-es"; import { useCategories, type TagEditDetailsInput, type TagFragment as Tag, } from "src/graphql"; import { EditNote } from "src/components/form"; import { LoadingIndicator } from "src/components/fragments"; import MultiSelect from "src/components/multiSelect"; import { TagSchema, type TagFormData } from "./schema"; import type { InitialTag } from "./types"; import { useBeforeUnload } from "src/hooks/useBeforeUnload"; interface TagProps { tag?: Tag | null; callback: (data: TagEditDetailsInput, editNote: string) => void; initial?: InitialTag; saving: boolean; } const TagForm: FC<TagProps> = ({ tag, callback, initial, saving }) => { useBeforeUnload(); const initialAliases = initial?.aliases ?? tag?.aliases ?? []; const { register, handleSubmit, formState: { errors }, control, } = useForm({ resolver: yupResolver(TagSchema), defaultValues: { name: initial?.name ?? tag?.name ?? "", description: initial?.description ?? tag?.description ?? "", aliases: initialAliases, category: initial?.category ?? tag?.category, }, }); const { loading: loadingCategories, data: categoryData } = useCategories(); if (loadingCategories) return <LoadingIndicator message="Loading tag categories..." />; const onSubmit = (data: TagFormData) => { const callbackData: TagEditDetailsInput = { name: data.name, description: data.description ?? null, aliases: data.aliases ?? [], category_id: data.category?.id, }; callback(callbackData, data.note); }; const categories = ( categoryData?.queryTagCategories.tag_categories ?? [] ).map((cat) => ({ label: cat.name, value: cat.id, group: cat.group, })); const grouped = groupBy(categories, (cat) => cat.group); const categoryObj = sortBy(Object.keys(grouped)).map((groupName) => ({ label: groupName, options: sortBy(grouped[groupName], (cat) => cat.label), })); return ( <Form className="TagForm w-50" onSubmit={handleSubmit(onSubmit)}> <Form.Group controlId="name" className="mb-3"> <Form.Label>Name</Form.Label> <Form.Control type="text" className={cx({ "is-invalid": errors.name })} placeholder="Name" {...register("name")} /> <div className="invalid-feedback">{errors?.name?.message}</div> </Form.Group> <Form.Group controlId="description" className="mb-3"> <Form.Label>Description</Form.Label> <Form.Control placeholder="Description" {...register("description")} /> </Form.Group> <Form.Group className="mb-3"> <Form.Label>Aliases</Form.Label> <Controller name="aliases" control={control} render={({ field: { onChange } }) => ( <MultiSelect initialValues={initialAliases} onChange={onChange} placeholder="Enter name..." /> )} /> </Form.Group> <Form.Group className="mb-3"> <Form.Label>Category</Form.Label> <Controller name="category" control={control} render={({ field: { onChange, value } }) => ( <Select classNamePrefix="react-select" className={cx({ "is-invalid": errors.category })} onChange={(opt) => onChange(opt ? { id: opt.value, name: opt.label } : null) } options={categoryObj} isClearable placeholder="Category" defaultValue={ value ? categories.find((s) => s.value === value.id) : null } /> )} /> <div className="invalid-feedback"> {(errors?.category as FieldError | undefined)?.message} </div> </Form.Group> <EditNote register={register} error={errors.note} /> <Form.Group className="d-flex mb-3"> <Button type="submit" disabled className="d-none" aria-hidden="true" /> <Button type="submit" disabled={saving}> Submit Edit </Button> <Button type="reset" className="ms-auto me-2"> Reset </Button> <Button variant="danger" onClick={() => history.back()}> Cancel </Button> </Form.Group> </Form> ); }; export default TagForm; ================================================ FILE: frontend/src/pages/tags/tagForm/diff.ts ================================================ import type { OldTagDetails, TagDetails, } from "src/components/editCard/ModifyEdit"; import type { TagFragment as Tag } from "src/graphql"; import type { TagFormData } from "./schema"; import { diffValue, diffArray } from "src/utils"; const selectTagDetails = ( data: TagFormData, original: Tag, ): [Required<OldTagDetails>, Required<TagDetails>] => { const [addedAliases, removedAliases] = diffArray( data?.aliases, original.aliases, (a) => a, ); return [ { name: diffValue(original.name, data.name), description: diffValue(original.description, data.description), category: original.category?.id !== data.category?.id && original.category?.id && original.category.name ? { id: original.category.id, name: original.category.name, } : null, }, { name: diffValue(data.name, original.name), description: diffValue(data.description, original.description), category: data.category?.id !== original.category?.id && data.category?.id && data.category?.name ? { id: data.category?.id, name: data.category?.name, } : null, added_aliases: addedAliases, removed_aliases: removedAliases, }, ]; }; export default selectTagDetails; ================================================ FILE: frontend/src/pages/tags/tagForm/index.ts ================================================ import TagForm from "./TagForm"; export default TagForm; ================================================ FILE: frontend/src/pages/tags/tagForm/schema.ts ================================================ import * as yup from "yup"; export const TagSchema = yup.object({ name: yup.string().trim().required("Name is required"), description: yup.string().trim(), aliases: yup.array().of(yup.string().trim().ensure()).ensure().default([]), category: yup .object({ id: yup.string().required(), name: yup.string().required(), }) .nullable() .default(null), note: yup.string().required("Edit note is required"), }); export type TagFormData = yup.Asserts<typeof TagSchema>; ================================================ FILE: frontend/src/pages/tags/tagForm/types.ts ================================================ export type InitialTag = { name?: string | null; description?: string | null; aliases?: string[]; category?: { id: string; name: string; } | null; }; ================================================ FILE: frontend/src/pages/users/GenerateInviteKeyModal.tsx ================================================ import { type FC, useState, useMemo } from "react"; import { Modal, Button, Form } from "react-bootstrap"; import type { GenerateInviteCodeInput } from "src/graphql"; import { formatDateTime } from "src/utils"; interface ModalProps { callback: (input?: GenerateInviteCodeInput) => void; } const ms = 1000; const minutesInSeconds = 60; const hoursInSeconds = 60 * minutesInSeconds; const daysInSeconds = 24 * hoursInSeconds; const yearsInSeconds = 365 * daysInSeconds; export const GenerateInviteKeyModal: FC<ModalProps> = ({ callback }) => { const [keyAmount, setKeyAmount] = useState(1); const [keyUses, setKeyUses] = useState(1); const [keyExpireAmount, setKeyExpireAmount] = useState(30); const [keyExpireUnit, setKeyExpireUnit] = useState(daysInSeconds); const handleCancel = () => callback(); const handleAccept = () => callback({ keys: keyAmount, uses: keyUses, ttl: keyExpireAmount * keyExpireUnit, }); const expireTime = useMemo(() => { const ret = new Date(); ret.setTime(ret.getTime() + keyExpireAmount * keyExpireUnit * ms); return ret; }, [keyExpireAmount, keyExpireUnit]); return ( <Modal show onHide={handleCancel}> <Modal.Header closeButton> <b>Generate Invite Keys</b> </Modal.Header> <Modal.Body> <Form> <Form.Group controlId="key-amount"> <Form.Label>Amount of Keys</Form.Label> <Form.Control value={keyAmount} onChange={(e) => setKeyAmount(parseInt(e.currentTarget.value, 10)) } type="number" min={1} max={100} placeholder="Enter number of keys" /> </Form.Group> <Form.Group controlId="key-uses" className="mt-4"> <Form.Label>Uses per key</Form.Label> <Form.Control value={keyUses} onChange={(e) => setKeyUses(parseInt(e.currentTarget.value, 10))} type="number" min={0} max={100} placeholder="Uses per key" /> <Form.Text className="text-muted"> Enter 0 for unlimited uses. </Form.Text> </Form.Group> <Form.Group controlId="key-expiration" className="mt-4"> <Form.Label>Expire time</Form.Label> <Form.Control type="number" min={1} value={keyExpireAmount} onChange={(e) => setKeyExpireAmount(parseInt(e.currentTarget.value, 10)) } /> <Form.Select value={keyExpireUnit} onChange={(e) => { setKeyExpireUnit(parseInt(e.currentTarget.value, 10)); }} className="mt-2" > <option value={minutesInSeconds}>Minutes</option> <option value={hoursInSeconds}>Hours</option> <option value={daysInSeconds}>Days</option> <option value={yearsInSeconds}>Years</option> </Form.Select> <Form.Text className="text-muted"> Expires at {formatDateTime(expireTime)} </Form.Text> </Form.Group> </Form> </Modal.Body> <Modal.Footer> <Button variant="primary" onClick={handleAccept}> Generate </Button> <Button variant="secondary" onClick={handleCancel}> Cancel </Button> </Modal.Footer> </Modal> ); }; ================================================ FILE: frontend/src/pages/users/User.tsx ================================================ import { type FC, useState } from "react"; import { Link } from "react-router-dom"; import { Button, Col, Form, InputGroup, Row, Table } from "react-bootstrap"; import { faMinus, faPlus, faSyncAlt, faTrash, } from "@fortawesome/free-solid-svg-icons"; import { sortBy } from "lodash-es"; import { VoteStatusEnum, VoteTypeEnum, useConfig, useDeleteUser, useRegenerateAPIKey, useRescindInviteCode, useGrantInvite, useRevokeInvite, type UserQuery, type PublicUserQuery, useGenerateInviteCodes, type GenerateInviteCodeInput, useRequestChangeEmail, } from "src/graphql"; import { useCurrentUser, useToast } from "src/hooks"; import { ROUTE_USER_EDIT, ROUTE_USER_PASSWORD, ROUTE_USERS, ROUTE_USER_EDITS, ROUTE_USER_MY_FINGERPRINTS, } from "src/constants/route"; import Modal from "src/components/modal"; import { Icon, Tooltip } from "src/components/fragments"; import { isPrivateUser, createHref, formatDateTime } from "src/utils"; import { EditStatusTypes, VoteTypes } from "src/constants"; import { GenerateInviteKeyModal } from "./GenerateInviteKeyModal"; import { CombinedGraphQLErrors } from "@apollo/client"; interface IInviteKeys { id: string; uses?: number | null | undefined; expires?: string | null | undefined; } interface UserInviteKeysProps { inviteCodes: IInviteKeys[]; rescindInvite: (id: string) => void; } const UserInviteKeys: FC<UserInviteKeysProps> = ({ inviteCodes, rescindInvite, }) => { if (inviteCodes.length === 0) return null; return ( <Table> <thead> <tr> <th>Code</th> <th>Uses</th> <th>Expires</th> <th></th> </tr> </thead> <tbody> {inviteCodes.map((ic) => ( <tr key={ic.id}> <td> <InputGroup className="mb-2"> <InputGroup.Text> <code>{ic.id}</code> </InputGroup.Text> <Button onClick={() => navigator.clipboard?.writeText(ic.id)}> Copy </Button> </InputGroup> </td> <td>{(ic.uses ?? 0) === 0 ? "unlimited" : ic.uses}</td> <td> {ic.expires ? ( <span>{formatDateTime(ic.expires, true)}</span> ) : ( "never" )} </td> <td> <Button variant="danger" onClick={() => rescindInvite(ic.id)}> <Icon icon={faTrash} /> </Button> </td> </tr> ))} </tbody> </Table> ); }; type User = NonNullable<UserQuery["findUser"]>; type EditCounts = User["edit_count"]; type VoteCounts = User["vote_count"]; type PublicUser = NonNullable<PublicUserQuery["findUser"]>; type EditCount = [VoteStatusEnum, number]; const filterEdits = (editCount: EditCounts): EditCount[] => { const edits = Object.entries(editCount) .map(([status, count]) => { const resolvedStatus = VoteStatusEnum[status.toUpperCase() as VoteStatusEnum]; return resolvedStatus ? [EditStatusTypes[resolvedStatus], count] : undefined; }) .filter((val): val is EditCount => val !== undefined); return sortBy(edits, (value) => value[0]); }; type VoteCount = [VoteTypeEnum, number]; const filterVotes = (voteCount: VoteCounts): VoteCount[] => { const votes = Object.entries(voteCount) .map(([status, count]) => { const resolvedStatus = VoteTypeEnum[status.toUpperCase() as VoteTypeEnum]; return resolvedStatus ? [VoteTypes[resolvedStatus], count] : undefined; }) .filter((val): val is VoteCount => val !== undefined); return sortBy(votes, (value) => value[0]); }; interface Props { user: User | PublicUser; refetch: () => void; } const UserComponent: FC<Props> = ({ user, refetch }) => { const { isAdmin, isSelf } = useCurrentUser(); const { data: configData } = useConfig(); const [showDelete, setShowDelete] = useState(false); const [showRegenerateAPIKey, setShowRegenerateAPIKey] = useState(false); const [showRescindCode, setShowRescindCode] = useState<string | undefined>(); const [showGenerateInviteKey, setShowGenerateInviteKey] = useState(false); const toast = useToast(); const [deleteUser, { loading: deleting }] = useDeleteUser(); const [regenerateAPIKey] = useRegenerateAPIKey(); const [rescindInviteCode] = useRescindInviteCode(); const [generateInviteCode] = useGenerateInviteCodes(); const [grantInvite] = useGrantInvite(); const [revokeInvite] = useRevokeInvite(); const [requestChangeEmail] = useRequestChangeEmail(); const showPrivate = isPrivateUser(user); const isOwner = showPrivate && isSelf(user); const endpointURL = configData && `${configData.getConfig.host_url}/graphql`; const toggleModal = () => setShowDelete(true); const handleDelete = (status: boolean): void => { if (status) deleteUser({ variables: { input: { id: user.id } } }).then(() => { window.location.href = ROUTE_USERS; }); setShowDelete(false); }; const deleteModal = showDelete && ( <Modal message={`Are you sure you want to delete '${user.name}'? This operation cannot be undone.`} callback={handleDelete} /> ); const handleRegenerateAPIKey = (status: boolean): void => { if (status) { const userID = isSelf(user.id) ? null : user.id; regenerateAPIKey({ variables: { user_id: userID } }).then(() => { refetch(); }); } setShowRegenerateAPIKey(false); }; const regenerateAPIKeyModal = showRegenerateAPIKey && ( <Modal callback={handleRegenerateAPIKey} acceptTerm="Confirm"> <p> Are you sure you want to regenerate the API key? The old key will be removed and can no longer be used. </p> <p> <i>This operation cannot be undone.</i> </p> </Modal> ); const handleRescindCode = (status: boolean): void => { if (status) { rescindInviteCode({ variables: { code: showRescindCode ?? "" } }).then( () => { refetch(); }, ); } setShowRescindCode(undefined); }; const rescindCodeModal = showRescindCode && ( <Modal message={`Are you sure you want to rescind code '${showRescindCode}'? This operation cannot be undone.`} callback={handleRescindCode} /> ); const handleGenerateCode = (input: GenerateInviteCodeInput) => { generateInviteCode({ variables: { input, }, }).then(() => { refetch(); }); }; const generateInviteCodeModal = showGenerateInviteKey && ( <GenerateInviteKeyModal callback={(i) => { if (i) { handleGenerateCode(i); } setShowGenerateInviteKey(false); }} /> ); const handleGrantInvite = () => { grantInvite({ variables: { input: { amount: 1, user_id: user.id, }, }, }).then(() => { refetch(); }); }; const handleRevokeInvite = () => { revokeInvite({ variables: { input: { amount: 1, user_id: user.id, }, }, }).then(() => { refetch(); }); }; const handleChangeEmail = () => { requestChangeEmail() .then(() => { toast({ variant: "success", content: ( <> <h5>Change email</h5> <div>Please check your existing email to continue.</div> </> ), }); }) .catch((error: unknown) => { let message: React.ReactNode | string | undefined = CombinedGraphQLErrors.is(error) && error.message; if (message === "pending-email-change") message = ( <> <h5>Pending email change</h5> <div>Email change already requested. Please try again later.</div> </> ); toast({ variant: "danger", content: message }); }); }; const editCount = filterEdits(user.edit_count); const voteCount = filterVotes(user.vote_count); return ( <Row className="justify-content-center"> <Col lg={10}> <div className="d-flex"> <h3>{user.name}</h3> {deleteModal} {regenerateAPIKeyModal} {generateInviteCodeModal} {rescindCodeModal} <div className="ms-auto"> <Link to={createHref(ROUTE_USER_EDITS, user)} className="ms-2"> <Button variant="secondary">User Edits</Button> </Link> {isOwner && ( <> <Link to={ROUTE_USER_MY_FINGERPRINTS} className="ms-2"> <Button variant="secondary">My Fingerprints</Button> </Link> <Link to={ROUTE_USER_PASSWORD} className="ms-2"> <Button>Change Password</Button> </Link> </> )} {isOwner && ( <Button onClick={() => handleChangeEmail()} className="ms-2"> Change Email </Button> )} {isAdmin && ( <> <Link to={createHref(ROUTE_USER_EDIT, user)} className="ms-2"> <Button>Edit User</Button> </Link> <Button className="ms-2" variant="danger" disabled={showDelete || deleting} onClick={toggleModal} > Delete User </Button> </> )} </div> </div> <hr /> {showPrivate && ( <> <Row> <Col xs={2}>Email</Col> <Col>{user.email}</Col> </Row> <Row> <Col xs={2}>Roles</Col> <Col>{(user.roles ?? []).join(", ")}</Col> </Row> <Row className="my-3 align-items-baseline"> <Col xs={2}>API key</Col> <Col xs={10}> <InputGroup> <Form.Control value={user.api_key ?? ""} disabled /> <Button onClick={() => navigator.clipboard?.writeText(user.api_key ?? "") } > Copy to Clipboard </Button> <Tooltip text="Regenerate API Key" placement="top-end"> <Button variant="danger" disabled={showRegenerateAPIKey} onClick={() => setShowRegenerateAPIKey(true)} > <Icon icon={faSyncAlt} /> </Button> </Tooltip> </InputGroup> </Col> </Row> {endpointURL && ( <Row className="my-3 align-items-baseline"> <Col xs={2}>GraphQL Endpoint</Col> <Col xs={10}> <InputGroup> <Form.Control value={endpointURL} disabled /> <Button onClick={() => navigator.clipboard?.writeText(endpointURL) } > Copy to Clipboard </Button> </InputGroup> </Col> </Row> )} </> )} <Row> <Col xs={6}> <Table> <thead> <tr> <th>Edits</th> <th>Count</th> </tr> </thead> <tbody> {editCount.map(([status, count]) => ( <tr key={status}> <td>{status}</td> <td>{count}</td> </tr> ))} </tbody> </Table> </Col> <Col xs={6}> <Table> <thead> <tr> <th>Votes</th> <th>Count</th> </tr> </thead> <tbody> {voteCount.map(([vote, count]) => ( <tr key={vote}> <td>{vote}</td> <td>{count}</td> </tr> ))} </tbody> </Table> </Col> </Row> {showPrivate && ( <Row> <Col xs={2}>Invite Tokens</Col> <InputGroup className="col"> {isAdmin && ( <Button onClick={() => handleRevokeInvite()}> <Icon icon={faMinus} /> </Button> )} <InputGroup.Text>{user.invite_tokens ?? 0}</InputGroup.Text> {isAdmin && ( <Button onClick={() => handleGrantInvite()}> <Icon icon={faPlus} /> </Button> )} </InputGroup> </Row> )} {showPrivate && ( <div> <Row> <Col xs={2}>Invite Keys</Col> </Row> <Row className="my-2"> <Col> <div> {isOwner && ( <Button variant="link" onClick={() => setShowGenerateInviteKey(true)} disabled={user.invite_tokens === 0} > <Icon icon={faPlus} className="me-2" /> Generate Key </Button> )} </div> <UserInviteKeys inviteCodes={user.invite_codes ?? []} rescindInvite={(c) => setShowRescindCode(c)} /> </Col> </Row> </div> )} </Col> </Row> ); }; export default UserComponent; ================================================ FILE: frontend/src/pages/users/UserAdd.tsx ================================================ import { type FC, useState } from "react"; import { useNavigate } from "react-router-dom"; import { CombinedGraphQLErrors } from "@apollo/client"; import { useAddUser } from "src/graphql"; import { ROUTE_USERS } from "src/constants/route"; import UserForm, { type UserData } from "./UserForm"; const AddUserComponent: FC = () => { const [queryError, setQueryError] = useState<string>(); const navigate = useNavigate(); const [insertUser] = useAddUser({ onCompleted: () => { window.location.href = ROUTE_USERS; }, }); const doInsert = (userData: UserData) => { insertUser({ variables: { userData } }) .then(() => navigate(ROUTE_USERS)) .catch( (error: unknown) => CombinedGraphQLErrors.is(error) && setQueryError(error.message), ); }; const emptyUser = { id: "", name: "", email: "", password: "", roles: [], }; return ( <div className="col-6"> <h3>Add user</h3> <hr /> <UserForm user={emptyUser} error={queryError} callback={doInsert} /> </div> ); }; export default AddUserComponent; ================================================ FILE: frontend/src/pages/users/UserConfirmChangeEmail.tsx ================================================ import { type FC, useState } from "react"; import { CombinedGraphQLErrors } from "@apollo/client"; import { useNavigate } from "react-router-dom"; import { Button, Form } from "react-bootstrap"; import type { User } from "src/context"; import { useQueryParams, useToast } from "src/hooks"; import { userHref } from "src/utils"; import { ErrorMessage } from "src/components/fragments"; import Title from "src/components/title"; import { useConfirmChangeEmail, UserChangeEmailStatus } from "src/graphql"; const ConfirmChangeEmail: FC<{ user: User }> = ({ user }) => { const navigate = useNavigate(); const [submitError, setSubmitError] = useState<string | undefined>(); const [{ token }] = useQueryParams({ token: { name: "key", type: "string" }, }); const toast = useToast(); const [confirmChangeEmail, { loading }] = useConfirmChangeEmail(); if (!token) return <ErrorMessage error="Missing key" />; if (submitError) return <ErrorMessage error={submitError} />; const onSubmit = () => { setSubmitError(undefined); confirmChangeEmail({ variables: { token } }) .then((res) => { const status = res.data?.confirmChangeEmail; if (status === UserChangeEmailStatus.SUCCESS) { toast({ variant: "success", content: ( <> <h5>Email successfully changed</h5> </> ), }); navigate(userHref(user)); } else if (status === UserChangeEmailStatus.INVALID_TOKEN) setSubmitError( "Invalid or expired token, please restart the process.", ); else if (status === UserChangeEmailStatus.EXPIRED) setSubmitError( "Email change token expired, please restart the process.", ); else setSubmitError("An unknown error occurred"); }) .catch( (error: unknown) => CombinedGraphQLErrors.is(error) && setSubmitError(error.message), ); return false; }; return ( <div className="LoginPrompt"> <Title page="Confirm Email change" /> <Form className="align-self-center col-8 mx-auto"> <h5>Confirm change email</h5> <p>Click the button to confirm email change.</p> <Button type="submit" disabled={loading} onClick={onSubmit}> Complete email change </Button> </Form> </div> ); }; export default ConfirmChangeEmail; ================================================ FILE: frontend/src/pages/users/UserEdit.tsx ================================================ import { type FC, useState } from "react"; import { useNavigate } from "react-router-dom"; import { CombinedGraphQLErrors } from "@apollo/client"; import { useUpdateUser, type PublicUserQuery, type UserQuery, } from "src/graphql"; import { userHref, isPrivateUser } from "src/utils"; import UserEditForm, { type UserEditData } from "./UserEditForm"; import { ErrorMessage } from "src/components/fragments"; type User = | NonNullable<UserQuery["findUser"]> | NonNullable<PublicUserQuery["findUser"]>; interface Props { user: User; } const EditUserComponent: FC<Props> = ({ user }) => { const [queryError, setQueryError] = useState<string>(); const navigate = useNavigate(); const [updateUser] = useUpdateUser(); if (!isPrivateUser(user)) return <ErrorMessage error="Access Denied" />; const doUpdate = (userData: UserEditData) => { updateUser({ variables: { userData } }) .then((res) => navigate(userHref(res.data?.userUpdate ?? user))) .catch( (error: unknown) => CombinedGraphQLErrors.is(error) && setQueryError(error.message), ); }; return ( <div> <h3>Edit ‘{user.name}’</h3> <hr /> <UserEditForm user={user} username={user.name} error={queryError} callback={doUpdate} /> </div> ); }; export default EditUserComponent; ================================================ FILE: frontend/src/pages/users/UserEditForm.tsx ================================================ import type { FC } from "react"; import { Button, Row, Form } from "react-bootstrap"; import { Link } from "react-router-dom"; import Select from "react-select"; import * as yup from "yup"; import { useForm, Controller } from "react-hook-form"; import { yupResolver } from "@hookform/resolvers/yup"; import cx from "classnames"; import { RoleEnum, type UserUpdateInput } from "src/graphql"; import { userHref } from "src/utils"; import { useCurrentUser } from "src/hooks"; const schema = yup.object({ name: yup.string().optional(), id: yup.string().required(), email: yup.string().email().required("Email is required"), roles: yup.array().of(yup.string().required()).required(), }); type UserFormData = yup.Asserts<typeof schema>; export type UserEditData = { name?: string; id: string; email: string; roles: RoleEnum[]; }; interface UserProps { user: UserUpdateInput; username: string; error?: string; callback: (data: UserEditData) => void; } const roles = Object.keys(RoleEnum).map((role) => ({ label: role, value: role, })); const UserForm: FC<UserProps> = ({ user, username, callback, error }) => { const { isAdmin } = useCurrentUser(); const { register, control, handleSubmit, formState: { errors }, } = useForm({ resolver: yupResolver(schema), }); const onSubmit = (formData: UserFormData) => { const userData = { ...formData, id: formData.id, email: formData.email, roles: formData.roles as RoleEnum[], }; callback(userData); }; return ( <Form onSubmit={handleSubmit(onSubmit)}> <Row> {isAdmin && ( <Form.Group controlId="name" className="col-6 mb-3"> <Form.Label>Username</Form.Label> <Form.Control className={cx({ "is-invalid": errors.name })} type="text" placeholder="Username" defaultValue={user.name ?? ""} {...register("name")} /> <div className="invalid-feedback">{errors?.name?.message}</div> </Form.Group> )} </Row> <Row> <Form.Control type="hidden" value={user.id} {...register("id")} /> <Form.Group controlId="email" className="col-6 mb-3"> <Form.Label>Email</Form.Label> <Form.Control className={cx({ "is-invalid": errors.email })} type="email" placeholder="Email" defaultValue={user.email ?? ""} {...register("email")} /> <div className="invalid-feedback">{errors?.email?.message}</div> </Form.Group> </Row> {isAdmin && ( <Row> <Form.Group className="col-6 mb-3"> <Form.Label>Roles</Form.Label> <Controller name="roles" control={control} defaultValue={(user.roles ?? []) as string[]} render={({ field: { onChange, value } }) => ( <Select classNamePrefix="react-select" name="roles" options={roles} placeholder="User roles" onChange={(vals) => onChange(vals.map((v) => v.value) ?? [])} defaultValue={roles.filter((r) => value.includes(r.value))} isMulti /> )} /> </Form.Group> </Row> )} <Row> <div className="col-6"> <Button variant="primary" type="submit"> Save </Button> <Link to={userHref({ name: username })} className="ms-2"> <Button variant="secondary">Cancel</Button> </Link> <div className="invalid-feedback d-block">{error}</div> </div> </Row> </Form> ); }; export default UserForm; ================================================ FILE: frontend/src/pages/users/UserEdits.tsx ================================================ import type { FC } from "react"; import { Link } from "react-router-dom"; import { ROUTE_USER } from "src/constants/route"; import { createHref } from "src/utils"; import { EditList } from "src/components/list"; import { VoteStatusEnum } from "src/graphql"; import { useCurrentUser } from "src/hooks"; interface Props { user: { id: string; name: string; }; } const UserEditsComponent: FC<Props> = ({ user }) => { const { isSelf } = useCurrentUser(); return ( <> <h3> Edits by <Link to={createHref(ROUTE_USER, user)}>{user.name}</Link> </h3> <EditList userId={user.id} defaultVoteStatus={VoteStatusEnum.PENDING} showVotedFilter={!isSelf(user)} userSubmitted={true} /> </> ); }; export default UserEditsComponent; ================================================ FILE: frontend/src/pages/users/UserFingerprints.tsx ================================================ import { UserFingerprintsList } from "./UserFingerprintsList"; const UserFingerprintsComponent = () => { const filter = { has_fingerprint_submissions: true, }; return ( <> <h3>My fingerprints</h3> <UserFingerprintsList filter={filter} /> </> ); }; export default UserFingerprintsComponent; ================================================ FILE: frontend/src/pages/users/UserFingerprintsList/UserFingerprint.tsx ================================================ import type { FC } from "react"; import { Button } from "react-bootstrap"; import type { FingerprintAlgorithm } from "src/graphql"; import { Icon } from "src/components/fragments"; import { formatDuration } from "src/utils"; import { faTimesCircle } from "@fortawesome/free-solid-svg-icons"; interface Props { fingerprint: { hash: string; duration: number; algorithm: FingerprintAlgorithm; }; deleteFingerprint: () => void; } export const UserFingerprint: FC<Props> = ({ fingerprint, deleteFingerprint, }) => ( <li> <div key={fingerprint.hash}> <b className="me-2">{fingerprint.algorithm}</b> {fingerprint.hash} ({formatDuration(fingerprint.duration)}) <Button className="text-danger ms-2" title="Submitted by you - click to remove submission" onClick={deleteFingerprint} variant="link" > <Icon icon={faTimesCircle} /> </Button> </div> </li> ); ================================================ FILE: frontend/src/pages/users/UserFingerprintsList/UserFingerprintsList.tsx ================================================ import { type FC, useState } from "react"; import { Button, Form, InputGroup, Row, Table } from "react-bootstrap"; import { faSortAmountUp, faSortAmountDown, } from "@fortawesome/free-solid-svg-icons"; import { useScenesWithFingerprints, type SceneQueryInput, SortDirectionEnum, SceneSortEnum, useUnmatchFingerprint, type FingerprintAlgorithm, CriterionModifier, } from "src/graphql"; import { usePagination, useQueryParams } from "src/hooks"; import { ensureEnum } from "src/utils"; import { ErrorMessage, Icon } from "src/components/fragments"; import List from "src/components/list/List"; import Modal from "src/components/modal"; import TagFilter from "src/components/tagFilter"; import UserSceneLine from "./UserSceneLine"; const PER_PAGE = 20; interface Props { perPage?: number; filter?: Partial<SceneQueryInput>; } const sortOptions = [ { value: SceneSortEnum.DATE, label: "Release Date" }, { value: SceneSortEnum.TITLE, label: "Title" }, { value: SceneSortEnum.TRENDING, label: "Trending" }, { value: SceneSortEnum.CREATED_AT, label: "Created At" }, { value: SceneSortEnum.UPDATED_AT, label: "Updated At" }, ]; export const UserFingerprintsList: FC<Props> = ({ perPage = PER_PAGE, filter, }) => { const [deletionCandidates, setDeletionCandidates] = useState< { hash: string; scene_id: string; algorithm: FingerprintAlgorithm; duration: number; }[] >([]); const [showDelete, setShowDelete] = useState(false); const [deleteFingerprint] = useUnmatchFingerprint(); const [params, setParams] = useQueryParams({ sort: { name: "sort", type: "string", default: SceneSortEnum.DATE }, dir: { name: "dir", type: "string", default: SortDirectionEnum.DESC }, tag: { name: "tag", type: "string" }, }); const sort = ensureEnum(SceneSortEnum, params.sort); const direction = ensureEnum(SortDirectionEnum, params.dir); const { page, setPage } = usePagination(); const { loading, data } = useScenesWithFingerprints({ input: { page, per_page: perPage, sort, direction, ...filter, tags: params.tag ? { value: [params.tag], modifier: CriterionModifier.INCLUDES } : undefined, }, submitted: true, }); if (!loading && !data) return <ErrorMessage error="Failed to load scenes." />; const filters = ( <InputGroup className="scene-sort w-auto"> <TagFilter tag={params.tag} onChange={(t) => setParams("tag", t?.id)} /> <Form.Select className="w-auto" onChange={(e) => setParams("sort", e.currentTarget.value.toLowerCase())} defaultValue={sort ?? "name"} > {sortOptions.map((s) => ( <option value={s.value} key={s.value}> {s.label} </option> ))} </Form.Select> <Button variant="secondary" onClick={() => setParams( "dir", direction === SortDirectionEnum.DESC ? SortDirectionEnum.ASC : SortDirectionEnum.DESC, ) } > <Icon icon={ direction === SortDirectionEnum.DESC ? faSortAmountDown : faSortAmountUp } /> </Button> </InputGroup> ); const deleteFingerprints = ( fingerprints: { scene_id: string; hash: string; algorithm: FingerprintAlgorithm; duration: number; }[], ) => { setDeletionCandidates(fingerprints); setShowDelete(true); }; const handleDelete = async (status: boolean) => { if (status && deletionCandidates.length) { for (const candidate of deletionCandidates) { await deleteFingerprint({ variables: candidate, }); } } setDeletionCandidates([]); setShowDelete(false); }; const deleteModal = showDelete && ( <Modal message={`Are you sure you want to delete ${deletionCandidates.length} fingerprints? This operation cannot be undone.`} callback={handleDelete} /> ); return ( <> {deleteModal} <List page={page} setPage={setPage} perPage={perPage} listCount={data?.queryScenes.count} loading={loading} filters={filters} entityName="scenes" > <Row> <Table striped variant="dark"> <thead> <tr> <th style={{ width: "50px" }}></th> <th>Title</th> <th>Studio</th> <th>Duration</th> <th style={{ width: "120px" }}>Release Date</th> </tr> </thead> <tbody> {data?.queryScenes.scenes.map((scene) => ( <UserSceneLine key={scene.id} scene={scene} deleteFingerprints={deleteFingerprints} /> ))} </tbody> </Table> </Row> </List> </> ); }; ================================================ FILE: frontend/src/pages/users/UserFingerprintsList/UserSceneLine.tsx ================================================ import type { FC } from "react"; import type { FingerprintAlgorithm, ScenesWithFingerprintsQuery, } from "src/graphql"; import { Icon } from "src/components/fragments"; import { Link } from "react-router-dom"; import { Button } from "react-bootstrap"; import { sceneHref, studioHref, formatDuration } from "src/utils"; import { faVideo, faTrashCan } from "@fortawesome/free-solid-svg-icons"; import { UserFingerprint } from "./UserFingerprint"; interface Props { scene: ScenesWithFingerprintsQuery["queryScenes"]["scenes"][number]; deleteFingerprints: ( fingerprints: { scene_id: string; hash: string; algorithm: FingerprintAlgorithm; duration: number; }[], ) => void; } const UserSceneLine: FC<Props> = ({ scene, deleteFingerprints }) => ( <> <tr key={scene.id}> <td> <Button variant="link" className="text-danger" onClick={() => deleteFingerprints( scene.fingerprints.map((fp) => ({ ...fp, scene_id: scene.id })), ) } > <Icon icon={faTrashCan} className="me-1" title="Delete all of your submitted fingerprints for this scene" /> </Button> </td> <td> <Link to={sceneHref(scene)}>{scene.title}</Link> </td> <td> {scene.studio && ( <Link to={studioHref(scene.studio)} className="text-truncate SceneCard-studio-name" > <Icon icon={faVideo} className="me-1" /> {scene.studio.name} </Link> )} </td> <td>{scene.duration ? formatDuration(scene.duration) : ""}</td> <td>{scene.release_date}</td> </tr> <tr key={`${scene.id}-fps`}> <td colSpan={4}> <ul> {scene.fingerprints.map((fp) => ( <UserFingerprint fingerprint={fp} deleteFingerprint={() => deleteFingerprints([{ ...fp, scene_id: scene.id }]) } key={fp.hash} /> ))} </ul> </td> </tr> </> ); export default UserSceneLine; ================================================ FILE: frontend/src/pages/users/UserFingerprintsList/index.ts ================================================ export * from "./UserFingerprintsList"; ================================================ FILE: frontend/src/pages/users/UserForm.tsx ================================================ import type { FC } from "react"; import { Button, Form, Row } from "react-bootstrap"; import { useNavigate } from "react-router-dom"; import Select from "react-select"; import * as yup from "yup"; import { useForm, Controller } from "react-hook-form"; import { yupResolver } from "@hookform/resolvers/yup"; import cx from "classnames"; import { RoleEnum, type UserUpdateInput } from "src/graphql"; const schema = yup.object({ id: yup.string(), name: yup.string().required("Username is required"), email: yup.string().email().required("Email is required"), password: yup .string() .min(8, "Password must be at least 8 characters") .test( "uniqueness", "Password must have at least 5 unique characters", (value) => value !== undefined && value .split("") .filter( (item: string, i: number, ar: string[]) => ar.indexOf(item) === i, ) .join("").length >= 5, ) .required("Password is required"), roles: yup.array().of(yup.string().required()).required(), }); type UserFormData = yup.Asserts<typeof schema>; export type UserData = { name: string; email: string; password: string; roles: RoleEnum[]; }; interface UserProps { user: UserUpdateInput; error?: string; callback: (data: UserData, id?: string) => void; } const roles = Object.keys(RoleEnum).map((role) => ({ label: role, value: role, })); const UserForm: FC<UserProps> = ({ user, callback, error }) => { const navigate = useNavigate(); const { register, handleSubmit, control, formState: { errors }, } = useForm({ resolver: yupResolver(schema), }); const onSubmit = (formData: UserFormData) => { const userData = { ...formData, name: formData.name, email: formData.email, password: formData.password, roles: formData.roles as RoleEnum[], }; callback(userData, formData.id); }; return ( <Form onSubmit={handleSubmit(onSubmit)}> <Row> <Form.Control type="hidden" value={user.id} /> <Form.Group controlId="username" className="col mb-3"> <Form.Label>Username</Form.Label> <Form.Control className={cx({ "is-invalid": errors.name })} placeholder="Username" defaultValue={user.name ?? ""} {...register("name")} /> <div className="invalid-feedback">{errors?.name?.message}</div> </Form.Group> </Row> <Row> <Form.Group controlId="email" className="col mb-3"> <Form.Label>Email</Form.Label> <Form.Control className={cx({ "is-invalid": errors.email })} type="email" placeholder="Email" defaultValue={user.email ?? ""} {...register("email")} /> <div className="invalid-feedback">{errors?.email?.message}</div> </Form.Group> </Row> <Row> <Form.Group controlId="password" className="col mb-3"> <Form.Label>Password</Form.Label> <Form.Control className={cx({ "is-invalid": errors.password })} type="password" placeholder="Password" defaultValue={user.password ?? ""} {...register("password")} /> <div className="invalid-feedback">{errors?.password?.message}</div> </Form.Group> </Row> <Row> <Form.Group className="col mb-3"> <Form.Label>Roles</Form.Label> <Controller name="roles" control={control} defaultValue={(user.roles ?? []) as string[]} render={({ field: { onChange, value } }) => ( <Select classNamePrefix="react-select" name="roles" options={roles} placeholder="User roles" onChange={(vals) => onChange(vals.map((v) => v.value) ?? [])} defaultValue={roles.filter((r) => value.includes(r.value))} isMulti /> )} /> </Form.Group> </Row> <Row> <div className="col"> <Button type="submit">Create</Button> <Button variant="secondary" className="ms-2" onClick={() => navigate(-1)} > Cancel </Button> <div className="invalid-feedback d-block">{error}</div> </div> </Row> </Form> ); }; export default UserForm; ================================================ FILE: frontend/src/pages/users/UserNotificationPreferences.tsx ================================================ import type { FC } from "react"; import { Button, Form } from "react-bootstrap"; import { Link } from "react-router-dom"; import { ROUTE_NOTIFICATIONS } from "src/constants/route"; import { NotificationEnum, useUpdateNotificationSubscriptions, } from "src/graphql"; import { NotificationType, ensureEnum, FavoriteNotificationType, } from "src/utils"; import { useCurrentUser } from "../../hooks"; interface Props { user: { id: string; notification_subscriptions: NotificationEnum[]; }; } export const UserNotificationPreferences: FC<Props> = ({ user }) => { const { isEditor } = useCurrentUser(); const subscribableNotificationTypes = Object.entries( isEditor ? NotificationType : FavoriteNotificationType, ); const [updateSubscriptions, { loading: submitting }] = useUpdateNotificationSubscriptions(); const activeNotifications: string[] = user.notification_subscriptions.map( (e) => e, ); const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => { e.preventDefault(); const data = new FormData(e.currentTarget); const subscriptions = data .getAll("subscriptions") .map((sub) => ensureEnum(NotificationEnum, sub.toString())); updateSubscriptions({ variables: { subscriptions } }); }; return ( <> <Link to={ROUTE_NOTIFICATIONS}> <h6 className="mb-4">← Notifications</h6> </Link> <h4>Active notification subscriptions</h4> <hr /> <Form onSubmit={handleSubmit}> {subscribableNotificationTypes.map(([key, value]) => ( <Form.Check value={key} defaultChecked={activeNotifications.includes(key)} id={key} label={value} key={key} name="subscriptions" /> ))} <div className="mt-4"> <Button type="reset" className="me-2"> Reset </Button> <Button type="submit" disabled={submitting}> Save </Button> </div> </Form> </> ); }; ================================================ FILE: frontend/src/pages/users/UserPassword.tsx ================================================ import { type FC, useState } from "react"; import { useNavigate } from "react-router-dom"; import { CombinedGraphQLErrors } from "@apollo/client"; import { useChangePassword } from "src/graphql"; import { userHref } from "src/utils"; import UserPassword, { type UserPasswordData } from "./UserPasswordForm"; import { useCurrentUser } from "src/hooks"; const ChangePasswordComponent: FC = () => { const { user } = useCurrentUser(); const [queryError, setQueryError] = useState<string>(); const navigate = useNavigate(); const [changePassword] = useChangePassword(); const doUpdate = (formData: UserPasswordData) => { const userData = { existing_password: formData.existingPassword, new_password: formData.newPassword, }; changePassword({ variables: { userData } }) .then(() => user && navigate(userHref(user))) .catch( (error) => CombinedGraphQLErrors.is(error) && setQueryError(error.message), ); }; return ( <div className="col-6"> <h3>Change Password</h3> <hr /> <UserPassword error={queryError} callback={doUpdate} /> </div> ); }; export default ChangePasswordComponent; ================================================ FILE: frontend/src/pages/users/UserPasswordForm.tsx ================================================ import type { FC } from "react"; import { Button, Form } from "react-bootstrap"; import * as yup from "yup"; import { useForm } from "react-hook-form"; import { yupResolver } from "@hookform/resolvers/yup"; import cx from "classnames"; import { useNavigate } from "react-router-dom"; const schema = yup.object({ id: yup.string(), existingPassword: yup.string().required("Existing password is required"), newPassword: yup .string() .min(8, "Password must be at least 8 characters") .test( "uniqueness", "Password must have at least 5 unique characters", (value) => value !== undefined && value .split("") .filter( (item: string, i: number, ar: string[]) => ar.indexOf(item) === i, ) .join("").length >= 5, ) .required("Password is required"), confirmNewPassword: yup .string() .nullable() .oneOf([yup.ref("newPassword"), null], "Passwords don't match") .required("Password is required"), }); type UserFormData = yup.InferType<typeof schema>; export type UserPasswordData = { newPassword: string; existingPassword: string; }; interface UserProps { error?: string; callback: (data: UserPasswordData) => void; } const UserForm: FC<UserProps> = ({ callback, error }) => { const navigate = useNavigate(); const { register, handleSubmit, formState: { errors }, } = useForm({ resolver: yupResolver(schema), }); const onSubmit = (formData: UserFormData) => { const userData = { existingPassword: formData.existingPassword, newPassword: formData.confirmNewPassword, }; callback(userData); }; return ( <Form onSubmit={handleSubmit(onSubmit)}> <Form.Group controlId="existingPassword" className="mb-3"> <Form.Control className={cx({ "is-invalid": errors.existingPassword })} type="password" placeholder="Existing Password" {...register("existingPassword")} /> <div className="invalid-feedback"> {errors?.existingPassword?.message} </div> </Form.Group> <Form.Group controlId="newPassword" className="mb-3"> <Form.Control className={cx({ "is-invalid": errors.newPassword })} type="password" placeholder="New Password" {...register("newPassword")} /> <div className="invalid-feedback">{errors?.newPassword?.message}</div> </Form.Group> <Form.Group controlId="confirmNewPassword" className="mb-3"> <Form.Control className={cx({ "is-invalid": errors.confirmNewPassword })} type="password" placeholder="Confirm New Password" {...register("confirmNewPassword")} /> <div className="invalid-feedback"> {errors?.confirmNewPassword?.message} </div> </Form.Group> <div> <Button type="submit">Save</Button> <Button variant="secondary" className="ms-2" onClick={() => navigate(-1)} > Cancel </Button> <div className="invalid-feedback d-block">{error}</div> </div> </Form> ); }; export default UserForm; ================================================ FILE: frontend/src/pages/users/UserValidateChangeEmail.tsx ================================================ import { type FC, useState } from "react"; import { yupResolver } from "@hookform/resolvers/yup"; import { useForm } from "react-hook-form"; import { CombinedGraphQLErrors } from "@apollo/client"; import * as yup from "yup"; import cx from "classnames"; import { Button, Form, Row, Col } from "react-bootstrap"; import type { User } from "src/context"; import { useQueryParams } from "src/hooks"; import { ErrorMessage } from "src/components/fragments"; import Title from "src/components/title"; import { useValidateChangeEmail, UserChangeEmailStatus } from "src/graphql"; const schema = yup.object({ token: yup.string().required(), email: yup.string().required("Email is required"), }); type ValidateChangeEmailFormData = yup.Asserts<typeof schema>; const ValidateChangeEmail: FC<{ user: User }> = () => { const [submitError, setSubmitError] = useState<string | undefined>(); const [{ token, submitted }, setQueryParam] = useQueryParams({ token: { name: "key", type: "string" }, submitted: { name: "submitted", type: "boolean" }, }); const { register, handleSubmit, formState: { errors }, } = useForm<ValidateChangeEmailFormData>({ resolver: yupResolver(schema), }); const [validateChangeEmail, { loading }] = useValidateChangeEmail(); if (submitted) return ( <div className="LoginPrompt"> <div className="align-self-center col-8 mx-auto"> <h5>Confirmation email sent</h5> <p>Please check your email to complete the email change.</p> </div> </div> ); if (!token) return <ErrorMessage error="Missing token" />; const onSubmit = (formData: ValidateChangeEmailFormData) => { setSubmitError(undefined); validateChangeEmail({ variables: { ...formData } }) .then((res) => { const status = res.data?.validateChangeEmail; if (status === UserChangeEmailStatus.CONFIRM_NEW) setQueryParam("submitted", true); else if (status === UserChangeEmailStatus.INVALID_TOKEN) setSubmitError( "Invalid or expired token, please restart the process.", ); else if (status === UserChangeEmailStatus.EXPIRED) setSubmitError( "Email change token expired, please restart the process.", ); else setSubmitError("An unknown error occurred"); }) .catch( (error: unknown) => CombinedGraphQLErrors.is(error) && setSubmitError(error.message), ); }; const errorList = [ errors.token?.message, errors.email?.message, submitError, ].filter((err): err is string => err !== undefined); return ( <div className="LoginPrompt"> <Title page="Confirm Email" /> <Form className="align-self-center col-8 mx-auto" onSubmit={handleSubmit(onSubmit)} > <h5>Change email</h5> <p>Enter a new email address to complete email change.</p> <Form.Control type="hidden" value={token} {...register("token")} /> <Form.Group controlId="email" className="mt-2"> <Form.Control className={cx({ "is-invalid": errors?.email })} type="email" placeholder="New email" {...register("email")} /> </Form.Group> {errorList.map((error) => ( <Row key={error} className="text-end text-danger"> <div>{error}</div> </Row> ))} <Row> <Col xs={{ span: 3, offset: 9 }} className="justify-content-end mt-2 d-flex" > <Button type="submit" disabled={loading}> Change Email </Button> </Col> </Row> </Form> </div> ); }; export default ValidateChangeEmail; ================================================ FILE: frontend/src/pages/users/Users.tsx ================================================ import type { FC } from "react"; import { Button, Form, Table } from "react-bootstrap"; import { Link } from "react-router-dom"; import { faUserEdit } from "@fortawesome/free-solid-svg-icons"; import { debounce } from "lodash-es"; import { useUsers } from "src/graphql"; import { usePagination, useQueryParams } from "src/hooks"; import { ErrorMessage, Icon } from "src/components/fragments"; import { List } from "src/components/list"; import { createHref } from "src/utils"; import { ROUTE_USER_EDIT, ROUTE_USER, ROUTE_USER_ADD, } from "src/constants/route"; const PER_PAGE = 20; const UsersComponent: FC = () => { const [{ query }, setParams] = useQueryParams({ query: { name: "query", type: "string", default: "" }, }); const { page, setPage } = usePagination(); const { loading, data } = useUsers({ input: { name: query.trim(), page, per_page: PER_PAGE, }, }); if (!loading && !data) return <ErrorMessage error="Failed to load users." />; const users = data?.queryUsers.users.map((user) => ( <tr key={user.id}> <td className="text-nowrap"> <Link to={createHref(ROUTE_USER_EDIT, user)}> <Button variant="secondary" className="minimal"> <Icon icon={faUserEdit} /> </Button> </Link> <Link to={createHref(ROUTE_USER, user)}> <Button variant="link"> <span>{user.name}</span> </Button> </Link> </td> <td>{user.email}</td> <td>{user?.roles?.join(", ") ?? ""}</td> <td>{user?.invited_by?.name ?? ""}</td> <td>{user?.invite_tokens ?? ""}</td> </tr> )); const debouncedHandler = debounce(setParams, 200); const filters = ( <Form.Control id="user-name" onChange={(e) => debouncedHandler("query", e.currentTarget.value)} placeholder="Filter by username" defaultValue={query ?? ""} className="w-auto" /> ); return ( <> <div className="d-flex"> <h3>Users</h3> <Link to={ROUTE_USER_ADD} className="ms-auto"> <Button>Add User</Button> </Link> </div> <List entityName="users" page={page} setPage={setPage} perPage={PER_PAGE} loading={loading} listCount={data?.queryUsers.count} filters={filters} > <Table striped className="users-table" variant="dark"> <thead> <tr> <th>Username</th> <th>Email</th> <th>Roles</th> <th>Invited by</th> <th>Invite Tokens</th> </tr> </thead> <tbody>{users}</tbody> </Table> </List> </> ); }; export default UsersComponent; ================================================ FILE: frontend/src/pages/users/index.tsx ================================================ import type { FC } from "react"; import { Route, Routes, useParams } from "react-router-dom"; import { useUser } from "src/graphql"; import Title from "src/components/title"; import { ErrorMessage, LoadingIndicator } from "src/components/fragments"; import Users from "./Users"; import User from "./User"; import UserAdd from "./UserAdd"; import UserEdit from "./UserEdit"; import UserPassword from "./UserPassword"; import UserEdits from "./UserEdits"; import UserConfirmChangeEmail from "./UserConfirmChangeEmail"; import UserValidateChangeEmail from "./UserValidateChangeEmail"; import UserFingerprints from "./UserFingerprints"; import { UserNotificationPreferences } from "./UserNotificationPreferences"; const UserLoader: FC = () => { const { name } = useParams<{ name: string }>(); const { data, loading, refetch } = useUser({ name: name ?? "" }); if (!name) return <ErrorMessage error="Tag ID is missing" />; if (loading) return <LoadingIndicator message="Loading user..." />; const user = data?.findUser; if (!user) return <ErrorMessage error="User not found." />; return ( <Routes> <Route path="/" element={ <> <Title page={user.name} /> <User user={user} refetch={refetch} /> </> } /> <Route path="/edit" element={ <> <Title page={`Edit ${user.name}`} /> <UserEdit user={user} /> </> } /> <Route path="/edits" element={ <> <Title page={`Edits by ${user.name}`} /> <UserEdits user={user} /> </> } /> <Route path="/confirm-email" element={<UserConfirmChangeEmail user={user} />} /> <Route path="/change-email" element={<UserValidateChangeEmail user={user} />} /> <Route path="/notifications" element={ "notification_subscriptions" in user ? ( <> <Title page={"Notification Preferences"} /> <UserNotificationPreferences user={user} /> </> ) : ( <ErrorMessage error="Forbidden" /> ) } /> </Routes> ); }; const UserRoutes: FC = () => ( <Routes> <Route path="/" element={ <> <Title page="Users" /> <Users /> </> } /> <Route path="/add" element={ <> <Title page="Add User" /> <UserAdd /> </> } /> <Route path="/change-password" element={ <> <Title page="Change Password" /> <UserPassword /> </> } /> <Route path="/fingerprints" element={ <> <Title page={"My Fingerprints"} /> <UserFingerprints /> </> } /> <Route path="/:name/*" element={<UserLoader />} /> </Routes> ); export default UserRoutes; ================================================ FILE: frontend/src/pages/users/styles.scss ================================================ .users-table { table-layout: fixed; .apikey { width: 50%; word-break: break-all; } } ================================================ FILE: frontend/src/pages/version/Version.tsx ================================================ import type { FC } from "react"; import { useVersion } from "src/graphql"; const Version: FC = () => { const { loading, data } = useVersion(); if (loading || !data) return null; let link = ""; switch (data.version.build_type) { case "OFFICIAL": link = `https://github.com/stashapp/stash-box/releases/tag/${data.version.version}`; break; case "DEVELOPMENT": case "PR": link = `https://github.com/stashapp/stash-box/commit/${data.version.hash}`; break; } return ( <dl> <dt>Version</dt> <dd> {link ? ( <a href={link}>{data.version.version}</a> ) : ( <span>{data.version.version}</span> )} </dd> <dt>Build Type</dt> <dd>{data.version.build_type}</dd> <dt>Build Hash</dt> <dd>{data.version.hash}</dd> <dt>Build Time</dt> <dd>{data.version.build_time}</dd> </dl> ); }; export default Version; ================================================ FILE: frontend/src/pages/version/index.ts ================================================ export { default } from "./Version"; ================================================ FILE: frontend/src/styles/theme.scss ================================================ // 1. Include functions first (so you can manipulate colors, SVGs, calc, etc) @import "bootstrap/scss/functions"; // 2. Include any default variable overrides here $primary: #137cbd; $secondary: #394b59; $success: #0f9960; $warning: #d9822b; $danger: #db3737; $dark: #394b59; $text-color: #f5f8fa; $muted-gray: #bfccd6; $text-muted: $muted-gray; $theme-colors: ( "primary": $primary, "secondary": $secondary, "success": $success, "warning": $warning, "danger": $danger, "dark": $dark, ); $link-color: #48aff0; $link-hover-color: $link-color; $pre-color: $text-color; $popover-bg: $secondary; // Custom variables $dark-text: #182026; $textfield-bg: rgba(16 22 26 / 30%); // 3. Include remainder of required Bootstrap stylesheets @import "bootstrap/scss/variables"; @import "bootstrap/scss/maps"; @import "bootstrap/scss/mixins"; // 4. Include any optional Bootstrap components as you like @import "bootstrap/scss/root"; @import "bootstrap/scss/reboot"; @import "bootstrap/scss/type"; @import "bootstrap/scss/containers"; @import "bootstrap/scss/grid"; @import "bootstrap/scss/helpers"; @import "bootstrap/scss/utilities"; @import "bootstrap/scss/utilities/api"; // Layout & components @import "bootstrap/scss/tables"; @import "bootstrap/scss/forms"; @import "bootstrap/scss/buttons"; @import "bootstrap/scss/nav"; @import "bootstrap/scss/navbar"; @import "bootstrap/scss/card"; @import "bootstrap/scss/pagination"; @import "bootstrap/scss/badge"; @import "bootstrap/scss/modal"; @import "bootstrap/scss/tooltip"; @import "bootstrap/scss/popover"; @import "bootstrap/scss/spinners"; @import "bootstrap/scss/close"; @import "bootstrap/scss/toasts"; @import "bootstrap/scss/alert"; @import "bootstrap/scss/dropdown"; /* @import "bootstrap/scss/images"; @import "bootstrap/scss/transitions"; @import "bootstrap/scss/button-group"; @import "bootstrap/scss/accordion"; @import "bootstrap/scss/breadcrumb"; @import "bootstrap/scss/progress"; @import "bootstrap/scss/list-group"; @import "bootstrap/scss/carousel"; @import "bootstrap/scss/offcanvas"; */ :root { --bs-primary: #{$primary}; --bs-secondary: #{$secondary}; --bs-success: #{$success}; --bs-warning: #{$warning}; --bs-danger: #{$danger}; --bs-body-bg: #202b33; --bs-dark: #{$dark}; --bs-dark-rgb: 57, 75, 89; } body { color: $text-color; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; min-width: 1210px; } .table { color: #f5f8fa; --bs-table-bg: transparent; --bs-table-striped-bg: rgba(92 112 128 / 15%); --bs-table-striped-color: #f5f8fa; td { border: none; padding: 0.25rem 0.75rem; vertical-align: middle; &:first-child { padding-left: 1rem; } } } .btn.active:not(.disabled), .btn.active.minimal:not(.disabled) { background-color: rgba(138 155 168 / 30%); color: $text-color; } .btn-link { text-decoration: none; &:hover { text-decoration: underline; } } a { color: unset; text-decoration: none; &:hover { color: unset; text-decoration: underline; } } a.minimal, button.minimal { background: none; border: none; color: $text-color; transition: none; &:hover { background: rgba(138 155 168 / 15%); color: $text-color; } &:active { background: rgba(138 155 168 / 30%); color: $text-color; } } a[aria-current] { font-weight: bold; } label.is-invalid { .error-message { color: red; } } hr { margin: 5px 0; background-color: rgba(0 0 0 / 10%); border-color: rgba(0 0 0 / 10%); opacity: 1; } .dropdown-toggle::after { content: none; } .nav-tabs { border: none; margin: auto; margin-bottom: 0.5rem; .nav-link { border: none; color: $text-color; padding: 8px; &.active { background-color: transparent; border-bottom: 2px solid; color: $link-color; &:hover { border-bottom-color: $link-color; cursor: default; } } &:hover { border-bottom: 2px solid white; } } } .navbar-dark .navbar-nav .nav-link { color: $text-color; &:hover { text-decoration: none; } } .tab-content { padding-bottom: 2rem; } .form-floating { .form-label { color: var(--bs-body-color); } } .form-control { &-plaintext { color: $text-color; margin: 0; padding: 0; option { color: black; } &::placeholder { color: transparent; } &:hover { cursor: default; } } } .popover { max-width: inherit; &-body { color: $text-color; white-space: pre-wrap; } } .modal { color: $text-color; .btn-close { background-color: $text-color; } &-header, &-body, &-footer { background-color: #30404d; border-color: transparent; color: $text-color; } &-content { background-color: transparent; } } .card { background-color: #30404d; border: none; border-radius: 3px; box-shadow: 0 0 0 1px rgba(16 22 26 / 40%), 0 0 0 rgba(16 22 26 / 0%), 0 0 0 rgba(16 22 26 / 0%); overflow: hidden; padding: 0; margin: calc($grid-gutter-width * 0.5) 0; &-footer, &-header { background-color: transparent; border: none; } } .page-link { background-color: var(--bs-secondary); border-bottom: none; border-left-color: var(--bs-body-bg); border-right-color: var(--bs-body-bg); border-top: none; color: white; } .page-link:focus { background-color: var(--bs-secondary); color: white; } .page-link:hover, .page-item.active .page-link { background-color: #2a3742; border-color: #25313a; color: white; z-index: 1; } .page-item:first-child .page-link { border-left-color: var(--bs-secondary); } .page-item:last-child .page-link { border-right-color: var(--bs-secondary); } .page-item.disabled .page-link { background-color: var(--bs-secondary); color: $gray-400; } .text-input, .input-control { border: 0; box-shadow: 0 0 0 0 rgba(19 124 189 / 0%), 0 0 0 0 rgba(19 124 189 / 0%), 0 0 0 0 rgba(19 124 189 / 0%), inset 0 0 0 1px rgba(16 22 26 / 30%), inset 0 1px 1px rgba(16 22 26 / 40%); color: $text-color; &:focus { border: 0; box-shadow: 0 0 0 1px $primary, 0 0 0 1px $primary, 0 0 0 3px rgba(19 124 189 / 30%), inset 0 0 0 1px rgba(16 22 26 / 30%), inset 0 1px 1px rgba(16 22 26 / 40%); color: $text-color; } } /* stylelint-disable no-descending-specificity */ .text-input, .text-input[readonly], .text-input:focus { background-color: $textfield-bg; } .input-control, .input-control:focus { background-color: $secondary; } /* stylelint-enable no-descending-specificity */ textarea.text-input { line-height: 2.5ex; min-height: 12ex; overflow-y: scroll; } .sr-only { @include visually-hidden; } ================================================ FILE: frontend/src/utils/country.ts ================================================ import Countries from "i18n-iso-countries"; import english from "i18n-iso-countries/langs/en.json"; Countries.registerLocale(english); const fuzzyDict: Record<string, string> = { USA: "US", "United States": "US", America: "US", American: "US", Czechia: "CZ", England: "GB", "United Kingdom": "GB", Russia: "RU", "Slovak Republic": "SK", }; export const getISOCountry = (country: string | null | undefined) => { if (!country) return null; const code = fuzzyDict[country] ?? Countries.getAlpha2Code(country, "en"); if (!code) return null; return { code, name: Countries.getName(code, "en"), }; }; export const getCountryByISO = (iso?: string | null) => { if (!iso) return null; const country = Countries.getName(iso, "en", { select: "alias" }); return country ?? null; }; ================================================ FILE: frontend/src/utils/createClient.ts ================================================ import { ApolloClient, InMemoryCache, ApolloLink, type TypePolicies, } from "@apollo/client"; import { ErrorLink } from "@apollo/client/link/error"; import { CombinedGraphQLErrors, ServerError } from "@apollo/client"; import { SetContextLink } from "@apollo/client/link/context"; import { RemoveTypenameFromVariablesLink } from "@apollo/client/link/remove-typename"; import UploadHttpLink from "apollo-upload-client/UploadHttpLink.mjs"; const typePolicies: TypePolicies = { SceneDraft: { keyFields: false, }, PerformerDraft: { keyFields: false, }, Studio: { fields: { sub_studios: { keyArgs: ["input"], }, }, }, Query: { fields: { findStudio: { merge: true, }, }, }, }; const isDevEnvironment = () => import.meta.env.DEV; export const getCredentialsSetting = () => isDevEnvironment() && !import.meta.env.VITE_SERVER_URL ? "include" : "same-origin"; export const getPlatformURL = () => { let platformUrl = new URL(window.location.origin); if (isDevEnvironment()) { platformUrl = new URL( import.meta.env.VITE_SERVER_URL ?? window.location.origin, ); platformUrl.port = import.meta.env.VITE_SERVER_PORT ?? "9998"; } return platformUrl; }; const httpLink = new UploadHttpLink({ uri: `${getPlatformURL().toString().slice(0, -1)}/graphql`, fetchOptions: { mode: "cors", credentials: getCredentialsSetting(), }, }); const authLink = new SetContextLink(({ headers, ...context }) => ({ headers: { ...headers, ...(import.meta.env.VITE_APIKEY && { ApiKey: import.meta.env.VITE_APIKEY, }), }, ...context, })); const errorLink = new ErrorLink(({ error }) => { if (CombinedGraphQLErrors.is(error)) { error.errors.forEach(({ message }) => { console.log(`GraphQL error: ${message}`); }); } else if (ServerError.is(error)) { console.log(`Server error: ${error.message}`); } else if (error) { console.log(`Other error: ${error.message}`); } }); const createClient = () => new ApolloClient({ link: ApolloLink.from([ authLink, errorLink, new RemoveTypenameFromVariablesLink(), httpLink, ]), cache: new InMemoryCache({ typePolicies }), }); export const setToken = (token: string) => { localStorage.setItem("token", token); }; export default createClient; ================================================ FILE: frontend/src/utils/data.ts ================================================ export const filterData = <T>(data?: (T | null | undefined)[] | null) => data ? (data.filter((item) => item) as T[]) : []; export const compareByName = <T extends { name: string }>(a: T, b: T) => a.name > b.name ? 1 : a.name < b.name ? -1 : 0; ================================================ FILE: frontend/src/utils/date.ts ================================================ import { Temporal } from "temporal-polyfill"; export const formatDateTime = (dateTime: Date | string, utc = false) => { const timeZone = utc ? "UTC" : undefined; const date = dateTime instanceof Date ? dateTime : new Date(dateTime); return `${date.toLocaleString("en-us", { month: "short", year: "numeric", day: "numeric", timeZone, })} ${date.toLocaleTimeString(navigator.languages[0], { timeZone, })}`; }; export const formatDate = (dateTime: Date | string, utc = false) => { const timeZone = utc ? "UTC" : undefined; const date = dateTime instanceof Date ? dateTime : new Date(dateTime); return date.toLocaleString("en-us", { month: "short", year: "numeric", day: "numeric", timeZone, }); }; export const formatISODate = (dateTime: Date | string) => { const date = dateTime instanceof Date ? dateTime : new Date(dateTime); return date.toISOString().slice(0, 10); }; const MIN_DATE = Temporal.PlainDate.from("1900-01-01"); export const maxBirthdate = () => Temporal.Now.plainDateISO().add({ years: -18 }); export const maxDeathdate = () => Temporal.Now.plainDateISO(); export const maxReleaseDate = () => Temporal.Now.plainDateISO().add({ years: 1 }); export const isInstantInFuture = (instant: Temporal.Instant) => Temporal.Instant.compare(instant, Temporal.Now.instant()) > 0; export const formatInstant = (instant: Temporal.Instant) => instant.toZonedDateTimeISO(Temporal.Now.timeZoneId()).toLocaleString(); export const isValidDate = (date?: string) => { if (!date) return true; try { Temporal.PlainDate.from(date); return true; } catch { return false; } }; export const isDateInRange = ( date: string | undefined, end?: Temporal.PlainDate, ) => { if (!date) return true; let parsedDate: Temporal.PlainDate; try { parsedDate = Temporal.PlainDate.from(date); } catch { return true; } if (Temporal.PlainDate.compare(parsedDate, MIN_DATE) < 0) return false; if (end && Temporal.PlainDate.compare(parsedDate, end) > 0) return false; return true; }; export const formatDistance = ( from: Temporal.Instant, to?: Temporal.Instant, ) => { const toInstant = to ?? Temporal.Now.instant(); const tz = Temporal.Now.timeZoneId(); const fromZDT = from.toZonedDateTimeISO(tz); const toZDT = toInstant.toZonedDateTimeISO(tz); const rough = fromZDT.since(toZDT, { largestUnit: "year" }); const rtf = new Intl.RelativeTimeFormat("en", { numeric: "auto" }); const round = (unit: Temporal.DateTimeUnit) => fromZDT.since(toZDT, { largestUnit: unit, smallestUnit: unit, roundingMode: "halfExpand", }); if (rough.years) return rtf.format(round("year").years, "year"); if (rough.months) return rtf.format(round("month").months, "month"); if (rough.days) return rtf.format(round("day").days, "day"); if (rough.hours) return rtf.format(round("hour").hours, "hour"); if (rough.minutes) return rtf.format(round("minute").minutes, "minute"); return rtf.format(round("second").seconds, "second"); }; export const parseDate = (date?: string): Temporal.PlainDate | undefined => { if (!date) return; try { return Temporal.PlainDate.from(date); } catch { return; } }; export const parseInstant = (date?: string): Temporal.Instant | undefined => { if (!date) return; try { return Temporal.Instant.from(date); } catch { return; } }; ================================================ FILE: frontend/src/utils/diff.ts ================================================ export const diffArray = <T>(a: T[], b: T[], getKey: (t: T) => string) => [ a.filter((x) => !b.some((val) => getKey(val) === getKey(x))), b.filter((x) => !a.some((val) => getKey(val) === getKey(x))), ]; export const diffValue = <T>( a: T | undefined | null, b: T | undefined | null, ): T | null => (a && a !== b ? a : null); export const diffImages = ( newImages: | { id: string | undefined; url: string | undefined; width: number | undefined; height: number | undefined; }[] | undefined, oldImages: { id: string; url: string; width: number; height: number }[], ) => diffArray( (newImages ?? []).flatMap((i) => i.id && i.url && i.height && i.width ? [ { id: i.id, url: i.url, width: i.width, height: i.height, }, ] : [], ), oldImages, (i) => i.id, ); export const diffURLs = ( newURLs: | { url: string | undefined; site: | { id: string | undefined; name: string | undefined; icon: string | undefined; } | undefined; }[] | undefined, originalURLs: { url: string; site: { id: string; name: string; icon: string; }; }[], ) => diffArray( (newURLs ?? []).map((u) => ({ url: u.url ?? "", site: { id: u.site?.id ?? "", name: u.site?.name ?? "", icon: u.site?.icon ?? "", }, })), originalURLs.map((u) => ({ url: u.url, site: { id: u.site.id, name: u.site.name, icon: u.site.icon, }, })), (u) => `${u.site.name ?? "Unknown"}: ${u.url}`, ); ================================================ FILE: frontend/src/utils/edit.ts ================================================ import type { EditsQuery } from "src/graphql"; import { ROUTE_HOME } from "src/constants/route"; import { performerHref, tagHref, studioHref, sceneHref } from "./route"; type Edits = NonNullable<EditsQuery["queryEdits"]["edits"][number]>; type Details = Edits["details"]; type Target = NonNullable<Edits["target"]>; type Tag = Target & { __typename: "Tag" }; type Performer = Target & { __typename: "Performer" }; type Studio = Target & { __typename: "Studio" }; type Scene = Target & { __typename: "Scene" }; interface TypeName { __typename: string; } export const isTag = ( entity: TypeName | null | undefined, ): entity is Tag | undefined => entity?.__typename === "Tag" || entity === undefined; export const isPerformer = ( entity: TypeName | null | undefined, ): entity is Performer | undefined => entity?.__typename === "Performer" || entity === undefined; export const isStudio = ( entity: TypeName | null | undefined, ): entity is Studio | undefined => entity?.__typename === "Studio" || entity === undefined; export const isScene = ( entity: TypeName | null | undefined, ): entity is Scene | undefined => entity?.__typename === "Scene" || entity === undefined; export const isTagEdit = <T extends TypeName>( details?: T | null, ): details is T & { __typename: "TagEdit" } => details?.__typename === "TagEdit"; export const isPerformerEdit = <T extends TypeName>( details?: T | null, ): details is T & { __typename: "PerformerEdit" } => details?.__typename === "PerformerEdit"; export const isStudioEdit = <T extends TypeName>( details?: T | null, ): details is T & { __typename: "StudioEdit" } => details?.__typename === "StudioEdit"; export const isSceneEdit = <T extends TypeName>( details?: T | null, ): details is T & { __typename: "SceneEdit" } => details?.__typename === "SceneEdit"; export const isValidEditTarget = ( target: Target | null | undefined, ): target is Performer | Tag | Studio | Scene => (isPerformer(target) || isTag(target) || isStudio(target) || isScene(target)) && target !== undefined; export const getEditTargetRoute = (target: Target): string => { if (isTag(target)) { return tagHref(target); } if (isPerformer(target)) { return performerHref(target); } if (isStudio(target)) { return studioHref(target); } if (isScene(target)) { return sceneHref(target); } return ROUTE_HOME; }; export const getEditTargetName = (target?: Target | null): string => { if (!target) return "-"; if (isScene(target)) { return target.title || target.id; } if (isPerformer(target)) { const disambiguation = target?.disambiguation ? ` (${target?.disambiguation})` : ""; return `${target?.name}${disambiguation}`; } return target.name || target.id; }; export const getEditTargetEntity = (target: Target) => { if (isTag(target)) { return "Tag"; } if (isPerformer(target)) { return "Performer"; } if (isStudio(target)) { return "Studio"; } if (isScene(target)) { return "Scene"; } }; export const getEditDetailsName = (details: Details | null): string => { if (isSceneEdit(details)) { return details.title ?? "-"; } if (isPerformerEdit(details)) { const disambiguation = details?.disambiguation ? ` (${details?.disambiguation})` : ""; return `${details?.name}${disambiguation}`; } return details?.name ?? "-"; }; ================================================ FILE: frontend/src/utils/enum.ts ================================================ import { BreastTypeEnum, FingerprintAlgorithm, EthnicityEnum, GenderEnum, NotificationEnum, } from "src/graphql"; export const genderEnum = ( gender: string | undefined | null, ): GenderEnum | null => gender === "MALE" ? GenderEnum.MALE : gender === "FEMALE" ? GenderEnum.FEMALE : gender === "NON_BINARY" ? GenderEnum.NON_BINARY : gender === "TRANSGENDER_MALE" ? GenderEnum.TRANSGENDER_MALE : gender === "TRANSGENDER_FEMALE" ? GenderEnum.TRANSGENDER_FEMALE : gender === "INTERSEX" ? GenderEnum.INTERSEX : null; export const ethnicityEnum = ( ethnicity: string | undefined | null, ): EthnicityEnum | null => { switch (ethnicity) { case "ASIAN": return EthnicityEnum.ASIAN; case "BLACK": return EthnicityEnum.BLACK; case "CAUCASIAN": return EthnicityEnum.CAUCASIAN; case "INDIAN": return EthnicityEnum.INDIAN; case "LATIN": return EthnicityEnum.LATIN; case "MIDDLE_EASTERN": return EthnicityEnum.MIDDLE_EASTERN; case "MIXED": return EthnicityEnum.MIXED; case "OTHER": return EthnicityEnum.OTHER; default: return null; } }; export const fingerprintAlgorithm = ( algorithm: string | undefined | null, ): FingerprintAlgorithm | null => algorithm === "MD5" ? FingerprintAlgorithm.MD5 : algorithm === "OSHASH" ? FingerprintAlgorithm.OSHASH : algorithm === "PHASH" ? FingerprintAlgorithm.PHASH : null; export const breastType = ( type: string | undefined | null, ): BreastTypeEnum | null => { switch (type) { case "FAKE": return BreastTypeEnum.FAKE; case "NA": return BreastTypeEnum.NA; case "NATURAL": return BreastTypeEnum.NATURAL; default: return null; } }; export const ensureEnum = <T>(enm: { [s: string]: T }, value: string): T => (Object.values(enm) as unknown as string[]).includes(value.toUpperCase()) ? (value.toUpperCase() as unknown as T) : Object.values(enm)[0]; export const resolveEnum = <T>( enm: { [s: string]: T }, value: string | null, defaultValue?: T, ): T | undefined => value && (Object.values(enm) as unknown as string[]).includes(value.toUpperCase()) ? (value.toUpperCase() as unknown as T) : defaultValue; export const FavoriteNotificationType = { [NotificationEnum.FAVORITE_PERFORMER_EDIT]: "An edit to a performer you have favorited, or a scene involving them.", [NotificationEnum.FAVORITE_STUDIO_EDIT]: "An edit to a studio you have favorited, or a scene from that studio.", [NotificationEnum.FAVORITE_STUDIO_SCENE]: "A new scene from a studio you have favorited.", [NotificationEnum.FAVORITE_PERFORMER_SCENE]: "A new scene involving a performer you have favorited.", } as const; export const NotificationType = { [NotificationEnum.UPDATED_EDIT]: "Updates to an edit you have voted on.", [NotificationEnum.COMMENT_OWN_EDIT]: "Comments on one of your edits", [NotificationEnum.DOWNVOTE_OWN_EDIT]: "Downvotes on one of your edits", [NotificationEnum.FAILED_OWN_EDIT]: "One of your edits have failed", [NotificationEnum.COMMENT_COMMENTED_EDIT]: "Comments on edits you have commented on", [NotificationEnum.COMMENT_VOTED_EDIT]: "Comments on edits you have voted on", [NotificationEnum.FINGERPRINTED_SCENE_EDIT]: "An edit to a scene you have submitted fingerprints for.", ...FavoriteNotificationType, } as const; ================================================ FILE: frontend/src/utils/general.ts ================================================ export const isUUID = (term: string): boolean => /^[a-f\d]{8}-[a-f\d]{4}-[a-f\d]{4}-[a-f\d]{4}-[a-f\d]{12}$/i.test(term); ================================================ FILE: frontend/src/utils/index.ts ================================================ export * from "./country"; export * from "./date"; export * from "./edit"; export * from "./general"; export * from "./transforms"; export * from "./route"; export * from "./markdown"; export * from "./enum"; export * from "./user"; export * from "./diff"; export * from "./data"; export * from "./intl"; export * from "./url"; ================================================ FILE: frontend/src/utils/intl.ts ================================================ const enOrdinalRules = new Intl.PluralRules("en-US", { type: "ordinal" }); const suffixes = new Map([ ["one", "st"], ["two", "nd"], ["few", "rd"], ["other", "th"], ]); export const formatOrdinals = (num: number) => { const rule = enOrdinalRules.select(num); const suffix = suffixes.get(rule); return `${num}${suffix}`; }; ================================================ FILE: frontend/src/utils/markdown.tsx ================================================ import type { FC } from "react"; import ReactMarkdown from "react-markdown"; import RemarkGFM from "remark-gfm"; import RemarkBreaks from "remark-breaks"; import RehypeExternalLinks from "rehype-external-links"; interface Props { text: string | null | undefined; unique?: string; } export const Markdown: FC<Props> = ({ text, unique }) => text ? ( <ReactMarkdown remarkPlugins={[RemarkGFM, RemarkBreaks]} rehypePlugins={[ [RehypeExternalLinks, { rel: ["nofollow", "noopener", "noreferrer"] }], ]} remarkRehypeOptions={{ clobberPrefix: unique ? `${unique}-` : undefined, }} disallowedElements={["img"]} components={{ input: (props) => ( <input className={props.type === "checkbox" ? "form-check-input" : ""} {...props} /> ), }} > {text} </ReactMarkdown> ) : null; ================================================ FILE: frontend/src/utils/route.ts ================================================ import { generatePath, matchPath } from "react-router-dom"; import { ROUTE_TAG, ROUTE_PERFORMER, ROUTE_CATEGORY, ROUTE_EDIT, ROUTE_STUDIO, ROUTE_SCENE, ROUTE_SITE, ROUTE_USER, } from "src/constants/route"; import { isUUID } from "./general"; export const userHref = (obj: { name: string }, route: string = ROUTE_USER) => generatePath(route, { name: obj.name ?? "_" }); export const sceneHref = (obj: { id: string }, route: string = ROUTE_SCENE) => generatePath(route, obj); export const studioHref = (obj: { id: string }, route: string = ROUTE_STUDIO) => generatePath(route, obj); export const editHref = (obj: { id: string }, route: string = ROUTE_EDIT) => generatePath(route, obj); export const categoryHref = ( obj: { id: string }, route: string = ROUTE_CATEGORY, ) => generatePath(route, obj); export const tagHref = (obj: { id: string }, route: string = ROUTE_TAG) => generatePath(route, { id: obj.id ?? "_" }); export const performerHref = ( obj: { id: string }, route: string = ROUTE_PERFORMER, ) => generatePath(route, obj); export const siteHref = (obj: { id: string }, route: string = ROUTE_SITE) => generatePath(route, obj); export const createHref = (route: string, params: unknown = {}) => generatePath( route, params as Record<string, string | number | boolean | undefined>, ); const ROUTES_WITH_ID = [ROUTE_PERFORMER, ROUTE_SCENE, ROUTE_STUDIO, ROUTE_TAG]; // Extracts a UUID from a local URL (e.g., /performers/{id}, /scenes/{id}) export const extractIdFromUrl = (text: string): string => { const trimmed = text.trim(); if (isUUID(trimmed)) { return trimmed; } try { const url = new URL(trimmed); // Only process URLs from the same origin if (url.origin !== window.location.origin) { return trimmed; } for (const route of ROUTES_WITH_ID) { const match = matchPath(route, url.pathname); if (match?.params.id && isUUID(match.params.id)) { return match.params.id; } } } catch { // Not a valid URL, return original text } return trimmed; }; ================================================ FILE: frontend/src/utils/transforms.ts ================================================ import type { UrlFragment } from "src/graphql"; export const formatCareer = ( start?: number | null, end?: number | null, ): string | undefined => start || end ? `Active ${start ?? "????"}\u2013${end ?? ""}` : undefined; export const formatMeasurements = ({ cup_size, band_size, hip_size, waist_size, }: { cup_size?: string | null; band_size?: number | null; waist_size?: number | null; hip_size?: number | null; }): string | undefined => { if (cup_size || band_size || hip_size || waist_size) { const bust = `${band_size ?? "?"}${cup_size ?? "?"}`; return `${bust}-${waist_size ?? "??"}-${hip_size ?? "??"}`; } return undefined; }; export const getBraSize = ( cup_size: string | null | undefined, band_size: number | null | undefined, ): string | undefined => band_size && cup_size ? `${band_size}${cup_size}` : undefined; type Image = { url: string; width: number; height: number; }; export const sortImageURLs = ( urls: Image[], orientation: "portrait" | "landscape", ) => urls .map((u) => ({ ...u, aspect: orientation === "portrait" ? u.height / u.width > 1 : u.width / u.height > 1, })) .sort((a, b) => { if (a.aspect > b.aspect) return -1; if (a.aspect < b.aspect) return 1; if (orientation === "portrait" && a.height > b.height) return -1; if (orientation === "portrait" && a.height < b.height) return 1; if (orientation === "landscape" && a.width > b.width) return -1; if (orientation === "landscape" && a.width < b.width) return 1; return 0; }); export const getImage = ( urls: Image[], orientation: "portrait" | "landscape", ) => { const images = sortImageURLs(urls, orientation); return images?.[0]?.url; }; export const imageType = (image?: Image) => { if (image && image.height > image.width) { return `vertical-img`; } else { return `horizontal-img`; } }; export const getUrlBySite = (urls: UrlFragment[], name: string) => urls.find((url) => url.site.name === name) ?? urls[0]; export const formatBodyModification = ( bodyMod?: { location: string; description?: string | null } | null, ) => bodyMod ? bodyMod.location + (bodyMod.description ? ` (${bodyMod.description})` : "") : null; export const formatBodyModifications = ( bodyMod?: { location: string; description?: string | null }[] | null, ) => (bodyMod ?? []).map(formatBodyModification).join(", "); export const formatPendingEdits = (count?: number) => count ? ` (${count} Pending)` : ""; export const formatDuration = (dur?: number | null) => { if (!dur) return ""; let value = dur; let hour = 0; let minute = 0; let seconds = 0; if (value >= 3600) { hour = Math.floor(value / 3600); value -= hour * 3600; } minute = Math.floor(value / 60); value -= minute * 60; seconds = value; const res = [ minute.toString().padStart(2, "0"), seconds.toString().padStart(2, "0"), ]; if (hour) res.unshift(hour.toString()); return res.join(":"); }; export const parseDuration = ( dur: string | null | undefined, ): number | null => { if (!dur) return null; const regex = /^((?<hours>\d+:)?(?<minutes>[0-5]?\d):)?(?<seconds>[0-5]?\d)$/; const matches = regex.exec(dur); const hours = matches?.groups?.hours ?? "0"; const minutes = matches?.groups?.minutes ?? "0"; const seconds = matches?.groups?.seconds ?? "0"; const duration = Number.parseInt(seconds, 10) + Number.parseInt(minutes, 10) * 60 + Number.parseInt(hours, 10) * 3600; return duration > 0 ? duration : null; }; export const parseBraSize = (braSize = ""): [string | null, number | null] => { const band = /^\d+/.exec(braSize)?.[0]; const bandSize = band ? Number.parseInt(band, 10) : null; const cup = bandSize ? braSize.replace(bandSize.toString(), "") : null; const cupSize = cup ? (/^[a-zA-Z]+/.exec(cup)?.[0]?.toUpperCase() ?? null) : null; return [cupSize, bandSize]; }; export const formatDisambiguation = ({ disambiguation, }: { disambiguation?: string | null; }) => (disambiguation ? ` (${disambiguation})` : ""); ================================================ FILE: frontend/src/utils/url.ts ================================================ export const cleanURL = ( regexStr: string | undefined | null, url: string, ): string | undefined => { if (!regexStr) return; const regex = new RegExp(regexStr); const match = regex.exec(url); if (match == null || match.length < 2) { return match?.[1]; } else { match.shift(); return match.join(""); } }; ================================================ FILE: frontend/src/utils/user.ts ================================================ import type { User } from "../context"; import { type UserQuery, type PublicUserQuery, RoleEnum } from "src/graphql"; type PrivateUser = NonNullable<UserQuery["findUser"]>; type PublicUser = NonNullable<PublicUserQuery["findUser"]>; const USER_STORAGE = "stash_box_user"; const cache = localStorage.getItem(USER_STORAGE); const cachedUser = cache ? (JSON.parse(cache) as User) : undefined; export const getCachedUser = () => cachedUser; export const setCachedUser = (user?: User | null) => { if (user) localStorage.setItem(USER_STORAGE, JSON.stringify(user)); else localStorage.removeItem(USER_STORAGE); }; export const isPrivateUser = ( user: PublicUser | PrivateUser, ): user is PrivateUser => !!(user as PrivateUser).email; export const isAdmin = (user?: User) => (user?.roles ?? []).includes(RoleEnum.ADMIN); export const canEdit = (user?: User) => (user?.roles ?? []).includes(RoleEnum.EDIT) || isAdmin(user); export const canTagEdit = (user?: User) => (user?.roles ?? []).includes(RoleEnum.EDIT_TAGS) || isAdmin(user); export const canVote = (user?: User) => (user?.roles ?? []).includes(RoleEnum.VOTE) || isAdmin(user); export const canModerate = (user?: User) => (user?.roles ?? []).includes(RoleEnum.MODERATE) || isAdmin(user); ================================================ FILE: frontend/tsconfig.json ================================================ { "compilerOptions": { "esModuleInterop": true, "module": "esnext", "moduleResolution": "bundler", "resolveJsonModule": true, "target": "ESNext", "jsx": "react-jsx", "lib": [ "dom", "dom.iterable", "esnext" ], "allowJs": true, "skipLibCheck": true, "strict": true, "forceConsistentCasingInFileNames": true, "isolatedModules": true, "noEmit": true, "paths": { "src/*": ["./src/*"] }, "noFallthroughCasesInSwitch": true, "types": [ "node", "vite/client" ] }, "include": [ "src/**/*" ] } ================================================ FILE: frontend/vite.config.mjs ================================================ import { defineConfig, loadEnv } from "vite"; import react from "@vitejs/plugin-react"; import graphqlPlugin from "vite-plugin-graphql-loader"; import analyzePlugin from "rollup-plugin-analyzer"; export default defineConfig(({ mode }) => { const env = { ...process.env, ...loadEnv(mode, process.cwd(), ""), }; /** @type {import("vite").UserConfig} */ const config = { build: { outDir: "build", assetsDir: "assets", sourcemap: mode === "production", }, optimizeDeps: { entries: "src/index.tsx", }, server: { port: Number(env.PORT) || undefined, }, plugins: [ react(), graphqlPlugin(), ], resolve: { tsconfigPaths: true } }; if (process.env.analyze) { config.plugins.push( analyzePlugin({ summaryOnly: true, limit: 30 }) ); } return config; }); ================================================ FILE: go.mod ================================================ module github.com/stashapp/stash-box go 1.25.0 require ( github.com/99designs/gqlgen v0.17.89 github.com/Masterminds/squirrel v1.5.4 github.com/davidbyttow/govips/v2 v2.18.0 github.com/disintegration/imaging v1.6.2 github.com/exaring/otelpgx v0.10.0 github.com/go-chi/chi/v5 v5.2.5 github.com/gofrs/uuid v4.3.1+incompatible github.com/golang-jwt/jwt/v5 v5.3.1 github.com/golang-migrate/migrate/v4 v4.19.1 github.com/gorilla/sessions v1.4.0 github.com/h2non/go-is-svg v0.0.0-20160927212452-35e8c4b0612c github.com/jackc/pgx/v5 v5.9.1 github.com/klauspost/compress v1.18.5 github.com/minio/minio-go/v7 v7.0.100 github.com/ravilushqa/otelgqlgen v0.19.0 github.com/riandyrn/otelchi v0.12.2 github.com/robfig/cron/v3 v3.0.1 github.com/rs/cors v1.11.1 github.com/sirupsen/logrus v1.9.4 github.com/spf13/pflag v1.0.10 github.com/spf13/viper v1.21.0 github.com/stretchr/testify v1.11.1 github.com/vektah/gqlparser/v2 v2.5.32 github.com/wneessen/go-mail v0.7.2 go.deanishe.net/favicon v0.1.0 go.opentelemetry.io/otel v1.43.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0 go.opentelemetry.io/otel/sdk v1.43.0 go.opentelemetry.io/otel/trace v1.43.0 golang.org/x/crypto v0.49.0 golang.org/x/image v0.38.0 golang.org/x/net v0.52.0 golang.org/x/sync v0.20.0 ) require ( cel.dev/expr v0.25.1 // indirect filippo.io/edwards25519 v1.1.1 // indirect github.com/PuerkitoBio/goquery v1.11.0 // indirect github.com/agnivade/levenshtein v1.2.1 // indirect github.com/andybalholm/cascadia v1.3.3 // indirect github.com/antlr4-go/antlr/v4 v4.13.1 // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cubicdaiya/gonp v1.0.4 // indirect github.com/dave/jennifer v1.6.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/fatih/structtag v1.2.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/friendsofgo/errors v0.9.2 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/go-ini/ini v1.67.0 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-sql-driver/mysql v1.9.2 // indirect github.com/go-viper/mapstructure/v2 v2.5.0 // indirect github.com/goccy/go-yaml v1.19.2 // indirect github.com/google/cel-go v0.24.1 // indirect github.com/google/uuid v1.6.0 // indirect github.com/gorilla/securecookie v1.1.2 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jmattheis/goverter v1.9.1 // indirect github.com/klauspost/cpuid/v2 v2.2.11 // indirect github.com/klauspost/crc32 v1.3.0 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect github.com/lib/pq v1.10.9 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/minio/crc64nvme v1.1.1 // indirect github.com/minio/md5-simd v1.1.2 // indirect github.com/ncruces/go-strftime v0.1.9 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pganalyze/pg_query_go/v6 v6.1.0 // indirect github.com/philhofer/fwd v1.2.0 // indirect github.com/pingcap/errors v0.11.5-0.20240311024730-e056997136bb // indirect github.com/pingcap/failpoint v0.0.0-20240528011301-b51a646c7c86 // indirect github.com/pingcap/log v1.1.0 // indirect github.com/pingcap/tidb/pkg/parser v0.0.0-20250324122243-d51e00e5bbf0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/riza-io/grpc-go v0.2.0 // indirect github.com/rs/xid v1.6.0 // indirect github.com/sagikazarmark/locafero v0.11.0 // indirect github.com/sergi/go-diff v1.4.0 // indirect github.com/sosodev/duration v1.4.0 // indirect github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect github.com/spf13/afero v1.15.0 // indirect github.com/spf13/cast v1.10.0 // indirect github.com/spf13/cobra v1.9.1 // indirect github.com/sqlc-dev/sqlc v1.29.0 // indirect github.com/stoewer/go-strcase v1.2.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/tetratelabs/wazero v1.9.0 // indirect github.com/tinylib/msgp v1.6.1 // indirect github.com/urfave/cli/v3 v3.7.0 // indirect github.com/vektah/dataloaden v0.3.0 // indirect github.com/wasilibs/go-pgquery v0.0.0-20250409022910-10ac41983c07 // indirect github.com/wasilibs/wazero-helpers v0.0.0-20240620070341-3dff1577cd52 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib v1.36.0 // indirect go.opentelemetry.io/otel/metric v1.43.0 // indirect go.opentelemetry.io/proto/otlp v1.10.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect golang.org/x/mod v0.33.0 // indirect golang.org/x/sys v0.42.0 // indirect golang.org/x/text v0.35.0 // indirect golang.org/x/tools v0.42.0 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 // indirect google.golang.org/grpc v1.80.0 // indirect google.golang.org/protobuf v1.36.11 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect modernc.org/libc v1.62.1 // indirect modernc.org/mathutil v1.7.1 // indirect modernc.org/memory v1.9.1 // indirect modernc.org/sqlite v1.37.0 // indirect ) tool ( github.com/99designs/gqlgen github.com/99designs/gqlgen/graphql/introspection github.com/jmattheis/goverter/cmd/goverter github.com/sqlc-dev/sqlc/cmd/sqlc github.com/vektah/dataloaden ) ================================================ FILE: go.sum ================================================ cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4= cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= filippo.io/edwards25519 v1.1.1 h1:YpjwWWlNmGIDyXOn8zLzqiD+9TyIlPhGFG96P39uBpw= filippo.io/edwards25519 v1.1.1/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/99designs/gqlgen v0.17.89 h1:KzEcxPiMgQoMw3m/E85atUEHyZyt0PbAflMia5Kw8z8= github.com/99designs/gqlgen v0.17.89/go.mod h1:GFqruTVGB7ZTdrf1uzOagpXbY7DrEt1pIxnTdhIbWvQ= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM= github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/PuerkitoBio/goquery v1.6.0/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= github.com/PuerkitoBio/goquery v1.11.0 h1:jZ7pwMQXIITcUXNH83LLk+txlaEy6NVOfTuP43xxfqw= github.com/PuerkitoBio/goquery v1.11.0/go.mod h1:wQHgxUOU3JGuj3oD/QFfxUdlzW6xPHfqyHre6VMY4DQ= github.com/agnivade/levenshtein v1.2.1 h1:EHBY3UOn1gwdy/VbFwgo4cxecRznFk7fKWN1KOX7eoM= github.com/agnivade/levenshtein v1.2.1/go.mod h1:QVVI16kDrtSuwcpd0p1+xMC6Z/VfhtCyDIjcwga4/DU= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM= github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA= github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ= github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/cubicdaiya/gonp v1.0.4 h1:ky2uIAJh81WiLcGKBVD5R7KsM/36W6IqqTy6Bo6rGws= github.com/cubicdaiya/gonp v1.0.4/go.mod h1:iWGuP/7+JVTn02OWhRemVbMmG1DOUnmrGTYYACpOI0I= github.com/dave/jennifer v1.6.0 h1:MQ/6emI2xM7wt0tJzJzyUik2Q3Tcn2eE0vtYgh4GPVI= github.com/dave/jennifer v1.6.0/go.mod h1:AxTG893FiZKqxy3FP1kL80VMshSMuz2G+EgvszgGRnk= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davidbyttow/govips/v2 v2.18.0 h1:pZRshWVYvewP/TZx3yZ7YeC42WyLXg53tHy5Qt8nT9E= github.com/davidbyttow/govips/v2 v2.18.0/go.mod h1:8+nst5zfMoats12PgmmAPh6p5OfjDaXK0BXMFl/vOcM= github.com/dgryski/trifles v0.0.0-20230903005119-f50d829f2e54 h1:SG7nF6SRlWhcT7cNTs5R6Hk4V2lcmLz2NsG2VnInyNo= github.com/dgryski/trifles v0.0.0-20230903005119-f50d829f2e54/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= github.com/dhui/dktest v0.4.6 h1:+DPKyScKSEp3VLtbMDHcUq6V5Lm5zfZZVb0Sk7Ahom4= github.com/dhui/dktest v0.4.6/go.mod h1:JHTSYDtKkvFNFHJKqCzVzqXecyv+tKt8EzceOmQOgbU= github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/docker/docker v28.3.3+incompatible h1:Dypm25kh4rmk49v1eiVbsAtpAsYURjYkaKubwuBdxEI= github.com/docker/docker v28.3.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/exaring/otelpgx v0.10.0 h1:NGGegdoBQM3jNZDKG8ENhigUcgBN7d7943L0YlcIpZc= github.com/exaring/otelpgx v0.10.0/go.mod h1:R5/M5LWsPPBZc1SrRE5e0DiU48bI78C1/GPTWs6I66U= github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/friendsofgo/errors v0.9.2 h1:X6NYxef4efCBdwI7BgS820zFaN7Cphrmb+Pljdzjtgk= github.com/friendsofgo/errors v0.9.2/go.mod h1:yCvFW5AkDIL9qn7suHVLiI/gH228n7PC4Pn44IGoTOI= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug= github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= github.com/go-openapi/strfmt v0.19.8/go.mod h1:qBBipho+3EoIqn6YDI+4RnQEtj6jT/IdKm+PAlXxSUc= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.9.2 h1:4cNKDYQ1I84SXslGddlsrMhc8k4LeDVj6Ad6WRjiHuU= github.com/go-sql-driver/mysql v1.9.2/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs= github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk= github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28= github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo= github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk= github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw= github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360= github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg= github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE= github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8= github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM= github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= github.com/gofrs/uuid v4.3.1+incompatible h1:0/KbAdpx3UXAx1kEOWHJeOkpbgRFGHVgv+CFIY7dBJI= github.com/gofrs/uuid v4.3.1+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang-migrate/migrate/v4 v4.19.1 h1:OCyb44lFuQfYXYLx1SCxPZQGU7mcaZ7gH9yH4jSFbBA= github.com/golang-migrate/migrate/v4 v4.19.1/go.mod h1:CTcgfjxhaUtsLipnLoQRWCrjYXycRz/g5+RWDuYgPrE= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/cel-go v0.24.1 h1:jsBCtxG8mM5wiUJDSGUqU0K7Mtr3w7Eyv00rw4DiZxI= github.com/google/cel-go v0.24.1/go.mod h1:Hdf9TqOaTNSFQA1ybQaRqATVoK7m/zcf7IMhGXP5zI8= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= github.com/gorilla/sessions v1.4.0 h1:kpIYOp/oi6MG/p5PgxApU8srsSw9tuFbt46Lt7auzqQ= github.com/gorilla/sessions v1.4.0/go.mod h1:FLWm50oby91+hl7p/wRxDth9bWSuk0qVL2emc7lT5ik= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs= github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c= github.com/h2non/go-is-svg v0.0.0-20160927212452-35e8c4b0612c h1:fEE5/5VNnYUoBOj2I9TP8Jc+a7lge3QWn9DKE7NCwfc= github.com/h2non/go-is-svg v0.0.0-20160927212452-35e8c4b0612c/go.mod h1:ObS/W+h8RYb1Y7fYivughjxojTmIu5iAIjSrSLCLeqE= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= github.com/jackc/pgx/v5 v5.9.1 h1:uwrxJXBnx76nyISkhr33kQLlUqjv7et7b9FjCen/tdc= github.com/jackc/pgx/v5 v5.9.1/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4= github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jedib0t/go-pretty v4.3.0+incompatible/go.mod h1:XemHduiw8R651AF9Pt4FwCTKeG3oo7hrHJAoznj9nag= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jmattheis/goverter v1.9.1 h1:3nLa+E5RzwJZik27/beP7RFe+KRaIl+MNV3HYsd0KeE= github.com/jmattheis/goverter v1.9.1/go.mod h1:3M72lCsCzbc+ACG+/tqNR3n3PVcxZK95aHiwHshPJQ8= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE= github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.11 h1:0OwqZRYI2rFrjS4kvkDnqJkKHdHaRnCm68/DY4OxRzU= github.com/klauspost/cpuid/v2 v2.2.11/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/klauspost/crc32 v1.3.0 h1:sSmTt3gUt81RP655XGZPElI0PelVTZ6YwCRnPSupoFM= github.com/klauspost/crc32 v1.3.0/go.mod h1:D7kQaZhnkX/Y0tstFGf8VUzv2UofNGqCjnC3zdHB0Hw= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw= github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk= github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/minio/crc64nvme v1.1.1 h1:8dwx/Pz49suywbO+auHCBpCtlW1OfpcLN7wYgVR6wAI= github.com/minio/crc64nvme v1.1.1/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg= github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= github.com/minio/minio-go/v7 v7.0.100 h1:ShkWi8Tyj9RtU57OQB2HIXKz4bFgtVib0bbT1sbtLI8= github.com/minio/minio-go/v7 v7.0.100/go.mod h1:EtGNKtlX20iL2yaYnxEigaIvj0G0GwSDnifnG8ClIdw= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pganalyze/pg_query_go/v6 v6.1.0 h1:jG5ZLhcVgL1FAw4C/0VNQaVmX1SUJx71wBGdtTtBvls= github.com/pganalyze/pg_query_go/v6 v6.1.0/go.mod h1:nvTHIuoud6e1SfrUaFwHqT0i4b5Nr+1rPWVds3B5+50= github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM= github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= github.com/pingcap/errors v0.11.0/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pingcap/errors v0.11.5-0.20240311024730-e056997136bb h1:3pSi4EDG6hg0orE1ndHkXvX6Qdq2cZn8gAPir8ymKZk= github.com/pingcap/errors v0.11.5-0.20240311024730-e056997136bb/go.mod h1:X2r9ueLEUZgtx2cIogM0v4Zj5uvvzhuuiu7Pn8HzMPg= github.com/pingcap/failpoint v0.0.0-20240528011301-b51a646c7c86 h1:tdMsjOqUR7YXHoBitzdebTvOjs/swniBTOLy5XiMtuE= github.com/pingcap/failpoint v0.0.0-20240528011301-b51a646c7c86/go.mod h1:exzhVYca3WRtd6gclGNErRWb1qEgff3LYta0LvRmON4= github.com/pingcap/log v1.1.0 h1:ELiPxACz7vdo1qAvvaWJg1NrYFoY6gqAh/+Uo6aXdD8= github.com/pingcap/log v1.1.0/go.mod h1:DWQW5jICDR7UJh4HtxXSM20Churx4CQL0fwL/SoOSA4= github.com/pingcap/tidb/pkg/parser v0.0.0-20250324122243-d51e00e5bbf0 h1:W3rpAI3bubR6VWOcwxDIG0Gz9G5rl5b3SL116T0vBt0= github.com/pingcap/tidb/pkg/parser v0.0.0-20250324122243-d51e00e5bbf0/go.mod h1:+8feuexTKcXHZF/dkDfvCwEyBAmgb4paFc3/WeYV2eE= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/ravilushqa/otelgqlgen v0.19.0 h1:LbgdvOeZLW3y6qJoZHu2qd1srsB2aYRDiY8moPfmZkQ= github.com/ravilushqa/otelgqlgen v0.19.0/go.mod h1:89WViMNkh5tnf6PYQGDFQDyLdhpQSlDdQ2/lYkdnlHg= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/riandyrn/otelchi v0.12.2 h1:6QhGv0LVw/dwjtPd12mnNrl0oEQF4ZAlmHcnlTYbeAg= github.com/riandyrn/otelchi v0.12.2/go.mod h1:weZZeUJURvtCcbWsdb7Y6F8KFZGedJlSrgUjq9VirV8= github.com/riza-io/grpc-go v0.2.0 h1:2HxQKFVE7VuYstcJ8zqpN84VnAoJ4dCL6YFhJewNcHQ= github.com/riza-io/grpc-go v0.2.0/go.mod h1:2bDvR9KkKC3KhtlSHfR3dAXjUMT86kg4UfWFyVGWqi8= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw= github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= github.com/sosodev/duration v1.4.0 h1:35ed0KiVFriGHHzZZJaZLgmTEEICIyt8Sx0RQfj9IjE= github.com/sosodev/duration v1.4.0/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= github.com/sqlc-dev/sqlc v1.29.0 h1:HQctoD7y/i29Bao53qXO7CZ/BV9NcvpGpsJWvz9nKWs= github.com/sqlc-dev/sqlc v1.29.0/go.mod h1:BavmYw11px5AdPOjAVHmb9fctP5A8GTziC38wBF9tp0= github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I= github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tinylib/msgp v1.6.1 h1:ESRv8eL3u+DNHUoSAAQRE50Hm162zqAnBoGv9PzScPY= github.com/tinylib/msgp v1.6.1/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77roAqEA= github.com/urfave/cli/v3 v3.7.0 h1:AGSnbUyjtLiM+WJUb4dzXKldl/gL+F8OwmRDtVr6g2U= github.com/urfave/cli/v3 v3.7.0/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso= github.com/vektah/dataloaden v0.3.0 h1:ZfVN2QD6swgvp+tDqdH/OIT/wu3Dhu0cus0k5gIZS84= github.com/vektah/dataloaden v0.3.0/go.mod h1:/HUdMve7rvxZma+2ZELQeNh88+003LL7Pf/CZ089j8U= github.com/vektah/gqlparser/v2 v2.5.32 h1:k9QPJd4sEDTL+qB4ncPLflqTJ3MmjB9SrVzJrawpFSc= github.com/vektah/gqlparser/v2 v2.5.32/go.mod h1:c1I28gSOVNzlfc4WuDlqU7voQnsqI6OG2amkBAFmgts= github.com/wasilibs/go-pgquery v0.0.0-20250409022910-10ac41983c07 h1:mJdDDPblDfPe7z7go8Dvv1AJQDI3eQ/5xith3q2mFlo= github.com/wasilibs/go-pgquery v0.0.0-20250409022910-10ac41983c07/go.mod h1:Ak17IJ037caFp4jpCw/iQQ7/W74Sqpb1YuKJU6HTKfM= github.com/wasilibs/wazero-helpers v0.0.0-20240620070341-3dff1577cd52 h1:OvLBa8SqJnZ6P+mjlzc2K7PM22rRUPE1x32G9DTPrC4= github.com/wasilibs/wazero-helpers v0.0.0-20240620070341-3dff1577cd52/go.mod h1:jMeV4Vpbi8osrE/pKUxRZkVaA0EX7NZN0A9/oRzgpgY= github.com/wneessen/go-mail v0.7.2 h1:xxPnhZ6IZLSgxShebmZ6DPKh1b6OJcoHfzy7UjOkzS8= github.com/wneessen/go-mail v0.7.2/go.mod h1:+TkW6QP3EVkgTEqHtVmnAE/1MRhmzb8Y9/W3pweuS+k= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.deanishe.net/favicon v0.1.0 h1:Afy941gjRik+DjUUcYHUxcztFEeFse2ITBkMMOlgefM= go.deanishe.net/favicon v0.1.0/go.mod h1:vIKVI+lUh8k3UAzaN4gjC+cpyatLQWmx0hVX4vLE8jU= go.mongodb.org/mongo-driver v1.4.2/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib v1.36.0 h1:ZeE8MRl6bAmxcjZeznBfqTe6syNvMKdxdBMzv6fDV94= go.opentelemetry.io/contrib v1.36.0/go.mod h1:V0PijCkYR5XurE5ytnNJuqWMXPW60jJTPXOiKj6nvhI= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q= go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 h1:88Y4s2C8oTui1LGM6bTWkw0ICGcOLCAI5l6zsD1j20k= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0/go.mod h1:Vl1/iaggsuRlrHf/hfPJPvVag77kKyvrLeD10kpMl+A= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0 h1:RAE+JPfvEmvy+0LzyUA25/SGawPwIUbZ6u0Wug54sLc= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0/go.mod h1:AGmbycVGEsRx9mXMZ75CsOyhSP6MFIcj/6dnG+vhVjk= go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g= go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw= golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.38.0 h1:5l+q+Y9JDC7mBOMjo4/aPhMDcxEptsX+Tt3GgRQRPuE= golang.org/x/image v0.38.0/go.mod h1:/3f6vaXC+6CEanU4KJxbcUZyEePbyKbaLoDOe4ehFYY= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190515012406-7d7faa4812bd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 h1:VPWxll4HlMw1Vs/qXtN7BvhZqsS9cdAittCNvVENElA= google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:7QBABkRtR8z+TEnmXTqIqwJLlzrZKVfAUm7tY3yGv0M= google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 h1:m8qni9SQFH0tJc1X0vmnpw/0t+AImlSvp30sEupozUg= google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM= google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= modernc.org/cc/v4 v4.25.2 h1:T2oH7sZdGvTaie0BRNFbIYsabzCxUQg8nLqCdQ2i0ic= modernc.org/cc/v4 v4.25.2/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= modernc.org/ccgo/v4 v4.25.1 h1:TFSzPrAGmDsdnhT9X2UrcPMI3N/mJ9/X9ykKXwLhDsU= modernc.org/ccgo/v4 v4.25.1/go.mod h1:njjuAYiPflywOOrm3B7kCB444ONP5pAVr8PIEoE0uDw= modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= modernc.org/libc v1.62.1 h1:s0+fv5E3FymN8eJVmnk0llBe6rOxCu/DEU+XygRbS8s= modernc.org/libc v1.62.1/go.mod h1:iXhATfJQLjG3NWy56a6WVU73lWOcdYVxsvwCgoPljuo= modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= modernc.org/memory v1.9.1 h1:V/Z1solwAVmMW1yttq3nDdZPJqV1rM05Ccq6KMSZ34g= modernc.org/memory v1.9.1/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8= modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= modernc.org/sqlite v1.37.0 h1:s1TMe7T3Q3ovQiK2Ouz4Jwh7dw4ZDqbebSDTlSJdfjI= modernc.org/sqlite v1.37.0/go.mod h1:5YiWv+YviqGMuGw4V+PNplcyaJ5v+vQd7TQOgkACoJM= modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= ================================================ FILE: gqlgen.yml ================================================ # Refer to https://gqlgen.com/config/ for detailed .gqlgen.yml documentation. schema: - "graphql/schema/types/*.graphql" - "graphql/schema/*.graphql" exec: filename: internal/models/generated_exec.go model: filename: internal/models/generated_models.go struct_tag: gqlgen autobind: - "github.com/stashapp/stash-box/internal/models" models: ID: model: github.com/stashapp/stash-box/internal/models.ID FingerprintHash: model: github.com/stashapp/stash-box/internal/models.FingerprintHash Image: model: github.com/stashapp/stash-box/internal/models.Image fields: url: resolver: true URLInput: model: github.com/stashapp/stash-box/internal/models.URL QueryPerformersResultType: model: github.com/stashapp/stash-box/internal/models.PerformerQuery QueryEditsResultType: model: github.com/stashapp/stash-box/internal/models.EditQuery QueryScenesResultType: model: github.com/stashapp/stash-box/internal/models.SceneQuery QueryModAuditsResultType: model: github.com/stashapp/stash-box/internal/models.ModAuditQuery omit_slice_element_pointers: true ================================================ FILE: graphql/schema/schema.graphql ================================================ """The query root for this schema""" type Query { #### Performers #### # performer names may not be unique """Find a performer by ID""" findPerformer(id: ID!): Performer @hasRole(role: READ) queryPerformers(input: PerformerQueryInput!): QueryPerformersResultType! @hasRole(role: READ) #### Studios #### # studio names should be unique """Find a studio by ID or name""" findStudio(id: ID, name: String): Studio @hasRole(role: READ) queryStudios(input: StudioQueryInput!): QueryStudiosResultType! @hasRole(role: READ) #### Tags #### # tag names will be unique """Find a tag by ID or name""" findTag(id: ID, name: String): Tag @hasRole(role: READ) """Find a tag with a matching name or alias""" findTagOrAlias(name: String!): Tag @hasRole(role: READ) queryTags(input: TagQueryInput!): QueryTagsResultType! @hasRole(role: READ) """Find a tag category by ID""" findTagCategory(id: ID!): TagCategory @hasRole(role: READ) queryTagCategories: QueryTagCategoriesResultType! @hasRole(role: READ) #### Scenes #### # ids should be unique """Find a scene by ID""" findScene(id: ID!): Scene @hasRole(role: READ) """Finds scenes that match a list of hashes""" findScenesBySceneFingerprints(fingerprints: [[FingerprintQueryInput!]!]!): [[Scene]!]! @hasRole(role: READ) queryScenes(input: SceneQueryInput!): QueryScenesResultType! @hasRole(role: READ) """Find an external site by ID""" findSite(id: ID!): Site @hasRole(role: READ) querySites: QuerySitesResultType! @hasRole(role: READ) #### Edits #### findEdit(id: ID!): Edit @hasRole(role: READ) queryEdits(input: EditQueryInput!): QueryEditsResultType! @hasRole(role: READ) #### Users #### """Find user by ID or username""" findUser(id: ID, username: String): User @hasRole(role: READ) queryUsers(input: UserQueryInput!): QueryUsersResultType! @hasRole(role: ADMIN) """Returns currently authenticated user""" me: User ### Full text search ### searchPerformer(term: String!, limit: Int): [Performer!]! @hasRole(role: READ) @deprecated(reason: "Use searchPerformers") searchPerformers(term: String!, limit: Int, page: Int, per_page: Int, filter: PerformerSearchFilter): QueryPerformersResultType! @hasRole(role: READ) searchScene(term: String!, limit: Int): [Scene!]! @hasRole(role: READ) @deprecated(reason: "Use searchScenes") searchScenes(term: String!, limit: Int, page: Int, per_page: Int): QueryScenesResultType! @hasRole(role: READ) searchTag(term: String!, limit: Int): [Tag!]! @hasRole(role: READ) searchStudio(term: String!, limit: Int): [Studio!]! @hasRole(role: READ) ### Drafts ### findDraft(id: ID!): Draft @hasRole(role: READ) findDrafts: [Draft!]! @hasRole(role: READ) ###Find scenes or pending scenes which match scene input### queryExistingScene(input: QueryExistingSceneInput!): QueryExistingSceneResult! @hasRole(role: READ) ###Find performers or pending performers which match performer input### queryExistingPerformer(input: QueryExistingPerformerInput!): QueryExistingPerformerResult! @hasRole(role: READ) #### Version #### version: Version! @hasRole(role: READ) ### Instance Config ### getConfig: StashBoxConfig! queryNotifications(input: QueryNotificationsInput!): QueryNotificationsResult! @hasRole(role: READ) getUnreadNotificationCount: Int! @hasRole(role: READ) ### Moderator Audits ### queryModAudits(input: ModAuditQueryInput!): QueryModAuditsResultType! @hasRole(role: ADMIN) } type Mutation { # Admin-only interface sceneCreate(input: SceneCreateInput!): Scene @hasRole(role: MODIFY) sceneUpdate(input: SceneUpdateInput!): Scene @hasRole(role: MODIFY) sceneDestroy(input: SceneDestroyInput!): Boolean! @hasRole(role: MODIFY) performerCreate(input: PerformerCreateInput!): Performer @hasRole(role: MODIFY) performerUpdate(input: PerformerUpdateInput!): Performer @hasRole(role: MODIFY) performerDestroy(input: PerformerDestroyInput!): Boolean! @hasRole(role: MODIFY) studioCreate(input: StudioCreateInput!): Studio @hasRole(role: MODIFY) studioUpdate(input: StudioUpdateInput!): Studio @hasRole(role: MODIFY) studioDestroy(input: StudioDestroyInput!): Boolean! @hasRole(role: MODIFY) tagCreate(input: TagCreateInput!): Tag @hasRole(role: MODIFY) tagUpdate(input: TagUpdateInput!): Tag @hasRole(role: MODIFY) tagDestroy(input: TagDestroyInput!): Boolean! @hasRole(role: MODIFY) userCreate(input: UserCreateInput!): User @hasRole(role: ADMIN) userUpdate(input: UserUpdateInput!): User @hasRole(role: ADMIN) userDestroy(input: UserDestroyInput!): Boolean! @hasRole(role: ADMIN) imageCreate(input: ImageCreateInput!): Image @hasRole(role: EDIT) imageDestroy(input: ImageDestroyInput!): Boolean! @hasRole(role: MODIFY) """User interface for registering""" newUser(input: NewUserInput!): ID activateNewUser(input: ActivateNewUserInput!): User generateInviteCode: ID @deprecated(reason: "Use generateInviteCodes") """Generates an invite code using an invite token""" generateInviteCodes(input: GenerateInviteCodeInput): [ID!]! """Removes a pending invite code - refunding the token""" rescindInviteCode(code: ID!): Boolean! """Adds invite tokens for a user""" grantInvite(input: GrantInviteInput!): Int! """Removes invite tokens from a user""" revokeInvite(input: RevokeInviteInput!): Int! tagCategoryCreate(input: TagCategoryCreateInput!): TagCategory @hasRole(role: ADMIN) tagCategoryUpdate(input: TagCategoryUpdateInput!): TagCategory @hasRole(role: ADMIN) tagCategoryDestroy(input: TagCategoryDestroyInput!): Boolean! @hasRole(role: ADMIN) siteCreate(input: SiteCreateInput!): Site @hasRole(role: ADMIN) siteUpdate(input: SiteUpdateInput!): Site @hasRole(role: ADMIN) siteDestroy(input: SiteDestroyInput!): Boolean! @hasRole(role: ADMIN) """Regenerates the api key for the given user, or the current user if id not provided""" regenerateAPIKey(userID: ID): String! """Generates an email to reset a user password""" resetPassword(input: ResetPasswordInput!): Boolean! """Changes the password for the current user""" changePassword(input: UserChangePasswordInput!): Boolean! """Request an email change for the current user""" requestChangeEmail: UserChangeEmailStatus! @hasRole(role: READ) validateChangeEmail(token: ID!, email: String!): UserChangeEmailStatus! @hasRole(role: READ) confirmChangeEmail(token: ID!): UserChangeEmailStatus! @hasRole(role: READ) # Edit interfaces """Propose a new scene or modification to a scene""" sceneEdit(input: SceneEditInput!): Edit! @hasRole(role: EDIT) """Propose a new performer or modification to a performer""" performerEdit(input: PerformerEditInput!): Edit! @hasRole(role: EDIT) """Propose a new studio or modification to a studio""" studioEdit(input: StudioEditInput!): Edit! @hasRole(role: EDIT) """Propose a new tag or modification to a tag""" tagEdit(input: TagEditInput!): Edit! @hasRole(role: EDIT) """Update a pending scene edit""" sceneEditUpdate(id: ID!, input: SceneEditInput!): Edit! @hasRole(role: EDIT) """Update a pending performer edit""" performerEditUpdate(id: ID!, input: PerformerEditInput!): Edit! @hasRole(role: EDIT) """Update a pending studio edit""" studioEditUpdate(id: ID!, input: StudioEditInput!): Edit! @hasRole(role: EDIT) """Update a pending tag edit""" tagEditUpdate(id: ID!, input: TagEditInput!): Edit! @hasRole(role: EDIT) """Vote to accept/reject an edit""" editVote(input: EditVoteInput!): Edit! @hasRole(role: VOTE) """Comment on an edit""" editComment(input: EditCommentInput!): Edit! @hasRole(role: EDIT) """Apply edit without voting""" applyEdit(input: ApplyEditInput!): Edit! @hasRole(role: ADMIN) """Cancel edit without voting""" cancelEdit(input: CancelEditInput!): Edit! @hasRole(role: EDIT) """Delete a closed edit - moderator only""" deleteEdit(input: DeleteEditInput!): Boolean! @hasRole(role: MODERATE) """Amend a closed edit by removing fields - moderator only""" amendEdit(input: AmendEditInput!): Edit! @hasRole(role: MODERATE) """Matches/unmatches a scene to fingerprint""" submitFingerprint(input: FingerprintSubmission!): Boolean! @hasRole(role: READ) """Batch submit up to 1000 fingerprint matches""" submitFingerprints(input: [FingerprintBatchSubmission!]!): [FingerprintSubmissionResult!]! @hasRole(role: READ) """Move all fingerprint submissions from source scene to target scene""" sceneMoveFingerprintSubmissions(input: MoveFingerprintSubmissionsInput!): Boolean! @hasRole(role: MODERATE) """Delete all fingerprint submissions for a specific fingerprint on a scene""" sceneDeleteFingerprintSubmissions(input: DeleteFingerprintSubmissionsInput!): Boolean! @hasRole(role: MODERATE) """Draft submissions""" submitSceneDraft(input: SceneDraftInput!): DraftSubmissionStatus! @hasRole(role: EDIT) submitPerformerDraft(input: PerformerDraftInput!): DraftSubmissionStatus! @hasRole(role: EDIT) destroyDraft(id: ID!): Boolean! @hasRole(role: EDIT) """Favorite or unfavorite a performer""" favoritePerformer(id: ID!, favorite: Boolean!): Boolean! @hasRole(role: READ) """Favorite or unfavorite a studio""" favoriteStudio(id: ID!, favorite: Boolean!): Boolean! @hasRole(role: READ) """Mark all of the current users notifications as read.""" markNotificationsRead(notification: MarkNotificationReadInput): Boolean! @hasRole(role: READ) """Update notification subscriptions for current user.""" updateNotificationSubscriptions(subscriptions: [NotificationEnum!]!): Boolean! @hasRole(role: READ) } schema { query: Query mutation: Mutation } ================================================ FILE: graphql/schema/types/config.graphql ================================================ type StashBoxConfig { host_url: String! require_invite: Boolean! require_activation: Boolean! vote_promotion_threshold: Int vote_application_threshold: Int! voting_period: Int! min_destructive_voting_period: Int! vote_cron_interval: String! guidelines_url: String! require_scene_draft: Boolean! edit_update_limit: Int! require_tag_role: Boolean! } ================================================ FILE: graphql/schema/types/draft.graphql ================================================ type DraftSubmissionStatus { id: ID } type DraftEntity { name: String! id: ID } input DraftEntityInput { name: String! id: ID } type Draft { id: ID! created: Time! expires: Time! data: DraftData! } union DraftData = SceneDraft | PerformerDraft ================================================ FILE: graphql/schema/types/edit.graphql ================================================ enum OperationEnum { CREATE MODIFY DESTROY MERGE } enum VoteTypeEnum { ABSTAIN ACCEPT REJECT """Immediately accepts the edit - bypassing the vote""" IMMEDIATE_ACCEPT """Immediately rejects the edit - bypassing the vote""" IMMEDIATE_REJECT } enum VoteStatusEnum { ACCEPTED REJECTED PENDING IMMEDIATE_ACCEPTED IMMEDIATE_REJECTED FAILED CANCELED } type EditVote { user: User date: Time! vote: VoteTypeEnum! } type EditComment { id: ID! user: User date: Time! comment: String! edit: Edit! } union EditDetails = PerformerEdit | SceneEdit | StudioEdit | TagEdit enum TargetTypeEnum { SCENE STUDIO PERFORMER TAG } union EditTarget = Performer | Scene | Studio | Tag type Edit { id: ID! user: User """Object being edited - null if creating a new object""" target: EditTarget target_type: TargetTypeEnum! """Objects to merge with the target. Only applicable to merges""" merge_sources: [EditTarget!]! operation: OperationEnum! bot: Boolean! details: EditDetails """Previous state of fields being modified - null if operation is create or delete.""" old_details: EditDetails """Entity specific options""" options: PerformerEditOptions comments: [EditComment!]! votes: [EditVote!]! """ = Accepted - Rejected""" vote_count: Int! """Is the edit considered destructive.""" destructive: Boolean! status: VoteStatusEnum! applied: Boolean! update_count: Int! updatable: Boolean! created: Time! updated: Time closed: Time expires: Time } input EditInput { """Not required for create type""" id: ID operation: OperationEnum! """Only required for merge type""" merge_source_ids: [ID!] comment: String """Edit submitted by an automated script. Requires bot permission""" bot: Boolean } input EditVoteInput { id: ID! vote: VoteTypeEnum! } input EditCommentInput { id: ID! comment: String! } type QueryEditsResultType { count: Int! edits: [Edit!]! } enum EditSortEnum { CREATED_AT UPDATED_AT CLOSED_AT } enum UserVotedFilterEnum { ABSTAIN ACCEPT REJECT NOT_VOTED } input EditQueryInput { """Filter by user id""" user_id: ID """Filter by status""" status: VoteStatusEnum """Filter by operation""" operation: OperationEnum """Filter by vote count""" vote_count: IntCriterionInput """Filter by applied status""" applied: Boolean """Filter by target type""" target_type: TargetTypeEnum """Filter by target id""" target_id: ID """Filter by favorite status""" is_favorite: Boolean """Filter by user voted status""" voted: UserVotedFilterEnum """Filter to bot edits only""" is_bot: Boolean """Filter out user's own edits""" include_user_submitted: Boolean page: Int! = 1 per_page: Int! = 25 direction: SortDirectionEnum! = DESC sort: EditSortEnum! = CREATED_AT } input ApplyEditInput { id: ID! } input CancelEditInput { id: ID! } input DeleteEditInput { id: ID! reason: String! } input AmendEditInput { id: ID! reason: String! """Fields to remove from the diff (e.g., ["name", "disambiguation"])""" remove_fields: [String!] """Array items to remove from added arrays""" remove_added_items: [AmendItemRemoval!] """Array items to remove from removed arrays""" remove_removed_items: [AmendItemRemoval!] } input AmendItemRemoval { """Field name (e.g., "aliases", "urls", "images")""" field: String! """Indices to remove from the array""" indices: [Int!]! } ================================================ FILE: graphql/schema/types/filter.graphql ================================================ input MultiIDCriterionInput { value: [ID!] modifier: CriterionModifier! } input IDCriterionInput { value: [ID!]! modifier: CriterionModifier! } input StringCriterionInput { value: String! modifier: CriterionModifier! } input MultiStringCriterionInput { value: [String!]! modifier: CriterionModifier! } input IntCriterionInput { value: Int! modifier: CriterionModifier! } input DateCriterionInput { value: Date! modifier: CriterionModifier! } enum CriterionModifier { """=""" EQUALS, """!=""" NOT_EQUALS, """>""" GREATER_THAN, """<""" LESS_THAN, """IS NULL""" IS_NULL, """IS NOT NULL""" NOT_NULL, """INCLUDES ALL""" INCLUDES_ALL, INCLUDES, EXCLUDES, } ================================================ FILE: graphql/schema/types/image.graphql ================================================ scalar Upload type Image { id: ID! url: String! width: Int! height: Int! } input ImageCreateInput { url: String file: Upload } input ImageUpdateInput { id: ID! url: String } input ImageDestroyInput { id: ID! } ================================================ FILE: graphql/schema/types/misc.graphql ================================================ scalar Date scalar DateTime scalar Time scalar FingerprintHash enum DateAccuracyEnum { YEAR MONTH DAY } type FuzzyDate { date: Date! accuracy: DateAccuracyEnum! } enum SortDirectionEnum { ASC DESC } type URL { url: String! type: String! @deprecated(reason: "Use the site field instead") site: Site! } input URLInput { url: String! site_id: ID! } ================================================ FILE: graphql/schema/types/mod_audit.graphql ================================================ enum ModAuditActionEnum { EDIT_DELETE EDIT_AMENDMENT } type ModAudit { id: ID! action: ModAuditActionEnum! user: User target_id: ID! target_type: String! data: String! reason: String created_at: Time! } type QueryModAuditsResultType { count: Int! audits: [ModAudit!]! } input ModAuditQueryInput { page: Int! = 1 per_page: Int! = 25 action: ModAuditActionEnum user_id: ID } ================================================ FILE: graphql/schema/types/notifications.graphql ================================================ type Notification { created: Time! read: Boolean! data: NotificationData! } enum NotificationEnum { FAVORITE_PERFORMER_SCENE FAVORITE_PERFORMER_EDIT FAVORITE_STUDIO_SCENE FAVORITE_STUDIO_EDIT COMMENT_OWN_EDIT DOWNVOTE_OWN_EDIT FAILED_OWN_EDIT COMMENT_COMMENTED_EDIT COMMENT_VOTED_EDIT UPDATED_EDIT FINGERPRINTED_SCENE_EDIT } union NotificationData = | FavoritePerformerScene | FavoritePerformerEdit | FavoriteStudioScene | FavoriteStudioEdit | CommentOwnEdit | CommentCommentedEdit | CommentVotedEdit | DownvoteOwnEdit | FailedOwnEdit | UpdatedEdit | FingerprintedSceneEdit type FavoritePerformerScene { scene: Scene! } type FavoritePerformerEdit { edit: Edit! } type FavoriteStudioScene { scene: Scene! } type FavoriteStudioEdit { edit: Edit! } type CommentOwnEdit { comment: EditComment! } type DownvoteOwnEdit { edit: Edit! } type FailedOwnEdit { edit: Edit! } type CommentCommentedEdit { comment: EditComment! } type CommentVotedEdit { comment: EditComment! } type UpdatedEdit { edit: Edit! } type FingerprintedSceneEdit { edit: Edit! } input QueryNotificationsInput { page: Int! = 1 per_page: Int! = 25 type: NotificationEnum unread_only: Boolean } type QueryNotificationsResult { count: Int! notifications: [Notification!]! } input MarkNotificationReadInput { type: NotificationEnum! id: ID! } ================================================ FILE: graphql/schema/types/performer.graphql ================================================ enum GenderEnum { MALE FEMALE TRANSGENDER_MALE TRANSGENDER_FEMALE INTERSEX NON_BINARY } enum GenderFilterEnum { UNKNOWN MALE FEMALE TRANSGENDER_MALE TRANSGENDER_FEMALE INTERSEX NON_BINARY } enum BreastTypeEnum { NATURAL FAKE NA } type Measurements { cup_size: String band_size: Int waist: Int hip: Int } enum EthnicityEnum { CAUCASIAN BLACK ASIAN INDIAN LATIN MIDDLE_EASTERN MIXED OTHER } enum EthnicityFilterEnum { UNKNOWN CAUCASIAN BLACK ASIAN INDIAN LATIN MIDDLE_EASTERN MIXED OTHER } enum EyeColorEnum { BLUE BROWN GREY GREEN HAZEL RED } enum HairColorEnum { BLONDE BRUNETTE BLACK RED AUBURN GREY BALD VARIOUS WHITE OTHER } type BodyModification { location: String! description: String } input BodyModificationInput { location: String! description: String } type Performer { id: ID! name: String! disambiguation: String aliases: [String!]! gender: GenderEnum urls: [URL!]! birthdate: FuzzyDate @deprecated(reason: "Please use `birth_date`") birth_date: String death_date: String age: Int # resolver ethnicity: EthnicityEnum country: String eye_color: EyeColorEnum hair_color: HairColorEnum """Height in cm""" height: Int measurements: Measurements! @deprecated(reason: "Use individual fields, cup/band/waist/hip_size") cup_size: String band_size: Int waist_size: Int hip_size: Int breast_type: BreastTypeEnum career_start_year: Int career_end_year: Int tattoos: [BodyModification!] piercings: [BodyModification!] images: [Image!]! deleted: Boolean! edits: [Edit!]! scene_count: Int! scenes(input: PerformerScenesInput): [Scene!]! """IDs of performers that were merged into this one""" merged_ids: [ID!]! """ID of performer that replaces this one""" merged_into_id: ID studios(studio_id: ID): [PerformerStudio!]! is_favorite: Boolean! created: Time! updated: Time! } input PerformerScenesInput { """Filter by another performer that also performs in the scenes""" performed_with: ID """Filter by a studio""" studio_id: ID """Filter by tags""" tags: MultiIDCriterionInput } type PerformerStudio { studio: Studio! scene_count: Int! } input PerformerCreateInput { name: String! disambiguation: String aliases: [String!] gender: GenderEnum urls: [URLInput!] birthdate: String deathdate: String ethnicity: EthnicityEnum country: String eye_color: EyeColorEnum hair_color: HairColorEnum height: Int cup_size: String band_size: Int waist_size: Int hip_size: Int breast_type: BreastTypeEnum career_start_year: Int career_end_year: Int tattoos: [BodyModificationInput!] piercings: [BodyModificationInput!] image_ids: [ID!] draft_id: ID } input PerformerUpdateInput { id: ID! name: String disambiguation: String aliases: [String!] gender: GenderEnum urls: [URLInput!] birthdate: String deathdate: String ethnicity: EthnicityEnum country: String eye_color: EyeColorEnum hair_color: HairColorEnum height: Int cup_size: String band_size: Int waist_size: Int hip_size: Int breast_type: BreastTypeEnum career_start_year: Int career_end_year: Int tattoos: [BodyModificationInput!] piercings: [BodyModificationInput!] image_ids: [ID!] } input PerformerDestroyInput { id: ID! } input PerformerEditDetailsInput { name: String disambiguation: String aliases: [String!] gender: GenderEnum urls: [URLInput!] birthdate: String deathdate: String ethnicity: EthnicityEnum country: String eye_color: EyeColorEnum hair_color: HairColorEnum height: Int cup_size: String band_size: Int waist_size: Int hip_size: Int breast_type: BreastTypeEnum career_start_year: Int career_end_year: Int tattoos: [BodyModificationInput!] piercings: [BodyModificationInput!] image_ids: [ID!] draft_id: ID } input PerformerEditOptionsInput { """Set performer alias on scenes without alias to old name if name is changed""" set_modify_aliases: Boolean = false """Set performer alias on scenes attached to merge sources to old name""" set_merge_aliases: Boolean = true } input PerformerEditInput { edit: EditInput! """Not required for destroy type""" details: PerformerEditDetailsInput """Controls aliases modification for merges and name modifications""" options: PerformerEditOptionsInput } type PerformerEdit { name: String disambiguation: String added_aliases: [String!] removed_aliases: [String!] gender: GenderEnum added_urls: [URL!] removed_urls: [URL!] birthdate: String deathdate: String ethnicity: EthnicityEnum country: String eye_color: EyeColorEnum hair_color: HairColorEnum """Height in cm""" height: Int cup_size: String band_size: Int waist_size: Int hip_size: Int breast_type: BreastTypeEnum career_start_year: Int career_end_year: Int added_tattoos: [BodyModification!] removed_tattoos: [BodyModification!] added_piercings: [BodyModification!] removed_piercings: [BodyModification!] added_images: [Image!] removed_images: [Image!] draft_id: ID aliases: [String!]! urls: [URL!]! images: [Image!]! tattoos: [BodyModification!]! piercings: [BodyModification!]! } type PerformerEditOptions { """Set performer alias on scenes without alias to old name if name is changed""" set_modify_aliases: Boolean! """Set performer alias on scenes attached to merge sources to old name""" set_merge_aliases: Boolean! } type GenderFacet { gender: GenderEnum! count: Int! } type PerformerSearchFacets { genders: [GenderFacet!]! } type QueryPerformersResultType { count: Int! performers: [Performer!]! """Search facets, only available for searchPerformer queries""" facets: PerformerSearchFacets } input BreastTypeCriterionInput { value: BreastTypeEnum modifier: CriterionModifier! } input EyeColorCriterionInput { value: EyeColorEnum modifier: CriterionModifier! } input HairColorCriterionInput { value: HairColorEnum modifier: CriterionModifier! } input BodyModificationCriterionInput { location: String description: String modifier: CriterionModifier! } enum PerformerSortEnum { NAME BIRTHDATE DEATHDATE SCENE_COUNT CAREER_START_YEAR DEBUT LAST_SCENE CREATED_AT UPDATED_AT } input PerformerSearchFilter { """Filter by gender""" gender: GenderEnum } input PerformerQueryInput { """Searches name and disambiguation - assumes like query unless quoted""" names: String """Searches name only - assumes like query unless quoted""" name: String """Search aliases only - assumes like query unless quoted""" alias: String disambiguation: StringCriterionInput gender: GenderFilterEnum """Filter to search urls - assumes like query unless quoted""" url: String birthdate: DateCriterionInput deathdate: DateCriterionInput birth_year: IntCriterionInput age: IntCriterionInput ethnicity: EthnicityFilterEnum country: StringCriterionInput eye_color: EyeColorCriterionInput hair_color: HairColorCriterionInput height: IntCriterionInput cup_size: StringCriterionInput band_size: IntCriterionInput waist_size: IntCriterionInput hip_size: IntCriterionInput breast_type: BreastTypeCriterionInput career_start_year: IntCriterionInput career_end_year: IntCriterionInput tattoos: BodyModificationCriterionInput piercings: BodyModificationCriterionInput """Filter by performerfavorite status for the current user""" is_favorite: Boolean """Filter by a performer they have performed in scenes with""" performed_with: ID """Filter by a studio""" studio_id: ID page: Int! = 1 per_page: Int! = 25 direction: SortDirectionEnum! = DESC sort: PerformerSortEnum! = CREATED_AT } type PerformerDraft { id: ID name: String! disambiguation: String aliases: String gender: String birthdate: String deathdate: String urls: [String!] ethnicity: String country: String eye_color: String hair_color: String height: String measurements: String breast_type: String tattoos: String piercings: String career_start_year: Int career_end_year: Int image: Image } input PerformerDraftInput { id: ID disambiguation: String name: String! aliases: String gender: String birthdate: String deathdate: String urls: [String!] ethnicity: String country: String eye_color: String hair_color: String height: String measurements: String breast_type: String tattoos: String piercings: String career_start_year: Int career_end_year: Int image: Upload } input QueryExistingPerformerInput { name: String disambiguation: String urls: [String!]! } type QueryExistingPerformerResult { edits: [Edit!]! performers: [Performer!]! } ================================================ FILE: graphql/schema/types/scene.graphql ================================================ type PerformerAppearance { performer: Performer! """Performing as alias""" as: String } input PerformerAppearanceInput { performer_id: ID! """Performing as alias""" as: String } enum FingerprintAlgorithm { MD5 OSHASH PHASH } enum FavoriteFilter { PERFORMER STUDIO ALL } enum FingerprintSubmissionType { "Positive vote" VALID "Report as invalid" INVALID "Remove vote" REMOVE } type Fingerprint { hash: FingerprintHash! algorithm: FingerprintAlgorithm! duration: Int! "number of times this fingerprint has been submitted (excluding reports)" submissions: Int! "number of times this fingerprint has been reported" reports: Int! created: Time! updated: Time! "true if the current user submitted this fingerprint" user_submitted: Boolean! "true if the current user reported this fingerprint" user_reported: Boolean! } type DraftFingerprint { hash: FingerprintHash! algorithm: FingerprintAlgorithm! duration: Int! } input FingerprintInput { """assumes current user if omitted. Ignored for non-modify Users""" user_ids: [ID!] hash: FingerprintHash! algorithm: FingerprintAlgorithm! duration: Int! } input FingerprintEditInput { user_ids: [ID!] hash: FingerprintHash! algorithm: FingerprintAlgorithm! duration: Int! created: Time! submissions: Int @deprecated(reason: "Unused") updated: Time @deprecated(reason: "Unused") } input FingerprintQueryInput { hash: FingerprintHash! algorithm: FingerprintAlgorithm! } input FingerprintSubmission { scene_id: ID! fingerprint: FingerprintInput! unmatch: Boolean @deprecated(reason: "Use `vote` with REMOVE instead") vote: FingerprintSubmissionType = VALID } input FingerprintBatchSubmission { scene_id: ID! hash: FingerprintHash! algorithm: FingerprintAlgorithm! duration: Int! } type FingerprintSubmissionResult { """The fingerprint hash that was submitted""" hash: FingerprintHash! """The scene ID that was submitted to""" scene_id: ID! """Error message if submission failed""" error: String } input MoveFingerprintSubmissionsInput { fingerprints: [FingerprintQueryInput!]! source_scene_id: ID! target_scene_id: ID! } input DeleteFingerprintSubmissionsInput { fingerprints: [FingerprintQueryInput!]! scene_id: ID! } type Scene { id: ID! title: String details: String date: String @deprecated(reason: "Please use `release_date` instead") release_date: String production_date: String urls: [URL!]! studio: Studio tags: [Tag!]! images: [Image!]! performers: [PerformerAppearance!]! fingerprints(is_submitted: Boolean = False): [Fingerprint!]! duration: Int director: String code: String deleted: Boolean! edits: [Edit!]! created: Time! updated: Time! } input SceneCreateInput { title: String details: String urls: [URLInput!] date: String! production_date: String studio_id: ID performers: [PerformerAppearanceInput!] tag_ids: [ID!] image_ids: [ID!] fingerprints: [FingerprintEditInput!]! duration: Int director: String code: String } input SceneUpdateInput { id: ID! title: String details: String urls: [URLInput!] date: String production_date: String studio_id: ID performers: [PerformerAppearanceInput!] tag_ids: [ID!] image_ids: [ID!] fingerprints: [FingerprintEditInput!] duration: Int director: String code: String } input SceneDestroyInput { id: ID! } input SceneEditDetailsInput { title: String details: String urls: [URLInput!] date: String production_date: String studio_id: ID performers: [PerformerAppearanceInput!] tag_ids: [ID!] image_ids: [ID!] duration: Int director: String code: String fingerprints: [FingerprintInput!] draft_id: ID } input SceneEditInput { edit: EditInput! """Not required for destroy type""" details: SceneEditDetailsInput } type SceneEdit { title: String details: String added_urls: [URL!] removed_urls: [URL!] date: String production_date: String studio: Studio """Added or modified performer appearance entries""" added_performers: [PerformerAppearance!] removed_performers: [PerformerAppearance!] added_tags: [Tag!] removed_tags: [Tag!] added_images: [Image!] removed_images: [Image!] added_fingerprints: [Fingerprint!] removed_fingerprints: [Fingerprint!] duration: Int director: String code: String draft_id: ID urls: [URL!]! performers: [PerformerAppearance!]! tags: [Tag!]! images: [Image!]! fingerprints: [Fingerprint!]! } type QueryScenesResultType { count: Int! scenes: [Scene!]! } enum SceneSortEnum { TITLE DATE TRENDING CREATED_AT UPDATED_AT } input SceneQueryInput { """Filter to search title and details - assumes like query unless quoted""" text: String """Filter to search title - assumes like query unless quoted""" title: String """Filter to search urls - assumes like query unless quoted""" url: String """Filter by date""" date: DateCriterionInput """Filter by production date""" production_date: DateCriterionInput """Filter to only include scenes with this studio""" studios: MultiIDCriterionInput """Filter to only include scenes with this studio as primary or parent""" parentStudio: String """Filter to only include scenes with these tags""" tags: MultiIDCriterionInput """Filter to only include scenes with these performers""" performers: MultiIDCriterionInput """Filter to include scenes with performer appearing as alias""" alias: StringCriterionInput """Filter to only include scenes with these fingerprints""" fingerprints: MultiStringCriterionInput """Filter by favorited entity""" favorites: FavoriteFilter """Filter to scenes with fingerprints submitted by the user""" has_fingerprint_submissions: Boolean = False page: Int! = 1 per_page: Int! = 25 direction: SortDirectionEnum! = DESC sort: SceneSortEnum! = DATE } union SceneDraftStudio = Studio | DraftEntity union SceneDraftPerformer = Performer | DraftEntity union SceneDraftTag = Tag | DraftEntity type SceneDraft { id: ID title: String code: String details: String director: String urls: [String!] date: String production_date: String studio: SceneDraftStudio performers: [SceneDraftPerformer!]! tags: [SceneDraftTag!] image: Image fingerprints: [DraftFingerprint!]! } input SceneDraftInput { id: ID title: String code: String details: String director: String url: String @deprecated(reason: "Use urls field instead.") urls: [String!] date: String production_date: String studio: DraftEntityInput performers: [DraftEntityInput!]! tags: [DraftEntityInput!] image: Upload fingerprints: [FingerprintInput!]! } input QueryExistingSceneInput { title: String studio_id: ID fingerprints: [FingerprintInput!]! } type QueryExistingSceneResult { edits: [Edit!]! scenes: [Scene!]! } ================================================ FILE: graphql/schema/types/site.graphql ================================================ type Site { id: ID! name: String! description: String url: String regex: String valid_types: [ValidSiteTypeEnum!]! icon: String! created: Time! updated: Time! } input SiteCreateInput { name: String! description: String url: String regex: String valid_types: [ValidSiteTypeEnum!]! } input SiteUpdateInput { id: ID! name: String! description: String url: String regex: String valid_types: [ValidSiteTypeEnum!]! } input SiteDestroyInput { id: ID! } type QuerySitesResultType { count: Int! sites: [Site!]! } enum ValidSiteTypeEnum { PERFORMER SCENE STUDIO } ================================================ FILE: graphql/schema/types/studio.graphql ================================================ type Studio { id: ID! name: String! aliases: [String!]! urls: [URL!]! parent: Studio child_studios: [Studio!]! @deprecated(reason: "Use sub_studios instead") sub_studios(input: StudioQueryInput): QueryStudiosResultType! images: [Image!]! deleted: Boolean! is_favorite: Boolean! created: Time! updated: Time! performers(input: PerformerQueryInput!): QueryPerformersResultType! } input StudioCreateInput { name: String! aliases: [String!] urls: [URLInput!] parent_id: ID image_ids: [ID!] } input StudioUpdateInput { id: ID! name: String aliases: [String!] urls: [URLInput!] parent_id: ID image_ids: [ID!] } input StudioDestroyInput { id: ID! } input StudioEditDetailsInput { name: String aliases: [String!] urls: [URLInput!] parent_id: ID image_ids: [ID!] } input StudioEditInput { edit: EditInput! """Not required for destroy type""" details: StudioEditDetailsInput } type StudioEdit { name: String """Added and modified URLs""" added_urls: [URL!] removed_urls: [URL!] parent: Studio added_images: [Image!] removed_images: [Image!] added_aliases: [String!] removed_aliases: [String!] images: [Image!]! urls: [URL!]! } type QueryStudiosResultType { count: Int! studios: [Studio!]! } enum StudioSortEnum { NAME CREATED_AT UPDATED_AT } input StudioQueryInput { """Filter to search name - assumes like query unless quoted""" name: String """Filter to search studio name, aliases and parent studio name - assumes like query unless quoted""" names: String """Filter to search url - assumes like query unless quoted""" url: String parent: IDCriterionInput has_parent: Boolean """Filter by studio favorite status for the current user""" is_favorite: Boolean page: Int! = 1 per_page: Int! = 25 direction: SortDirectionEnum! = ASC sort: StudioSortEnum! = NAME } ================================================ FILE: graphql/schema/types/tag.graphql ================================================ enum TagGroupEnum { PEOPLE SCENE ACTION } type Tag { id: ID! name: String! description: String aliases: [String!]! deleted: Boolean! edits: [Edit!]! category: TagCategory created: Time! updated: Time! } input TagCreateInput { name: String! description: String aliases: [String!] category_id: ID } input TagUpdateInput { id: ID! name: String description: String aliases: [String!] category_id: ID } input TagDestroyInput { id: ID! } input TagEditDetailsInput { name: String description: String aliases: [String!] category_id: ID } input TagEditInput { edit: EditInput! """Not required for destroy type""" details: TagEditDetailsInput } type TagEdit { name: String description: String added_aliases: [String!] removed_aliases: [String!] category: TagCategory aliases: [String!]! } type QueryTagsResultType { count: Int! tags: [Tag!]! } type QueryTagCategoriesResultType { count: Int! tag_categories: [TagCategory!]! } enum TagSortEnum { NAME CREATED_AT UPDATED_AT } input TagQueryInput { """Filter to search name, aliases and description - assumes like query unless quoted""" text: String """Searches name and aliases - assumes like query unless quoted""" names: String """Filter to search name - assumes like query unless quoted""" name: String """Filter to category ID""" category_id: ID page: Int! = 1 per_page: Int! = 25 direction: SortDirectionEnum! = ASC sort: TagSortEnum! = NAME } type TagCategory { id: ID! name: String! group: TagGroupEnum! description: String } input TagCategoryCreateInput { name: String! group: TagGroupEnum! description: String } input TagCategoryUpdateInput { id: ID! name: String group: TagGroupEnum description: String } input TagCategoryDestroyInput { id: ID! } ================================================ FILE: graphql/schema/types/user.graphql ================================================ directive @isUserOwner on FIELD_DEFINITION directive @hasRole(role: RoleEnum!) on FIELD_DEFINITION enum RoleEnum { READ VOTE EDIT MODIFY MODERATE ADMIN """May generate invites without tokens""" INVITE """May grant and rescind invite tokens and resind invite keys""" MANAGE_INVITES BOT READ_ONLY EDIT_TAGS } type InviteKey { id: ID! uses: Int expires: Time } type User { id: ID! name: String! """Should not be visible to other users""" roles: [RoleEnum!] @isUserOwner """Should not be visible to other users""" email: String @isUserOwner """Should not be visible to other users""" api_key: String @isUserOwner notification_subscriptions: [NotificationEnum!]! @isUserOwner """ Vote counts by type """ vote_count: UserVoteCount! """ Edit counts by status """ edit_count: UserEditCount! """Calls to the API from this user over a configurable time period""" api_calls: Int! @isUserOwner invited_by: User @isUserOwner invite_tokens: Int @isUserOwner active_invite_codes: [String!] @isUserOwner @deprecated(reason: "Use invite_codes instead") invite_codes: [InviteKey!] @isUserOwner } input UserCreateInput { name: String! """Password in plain text""" password: String! roles: [RoleEnum!]! email: String! invited_by_id: ID } input UserUpdateInput { id: ID! name: String """Password in plain text""" password: String roles: [RoleEnum!] email: String } input NewUserInput { email: String! invite_key: ID } input ActivateNewUserInput { name: String! activation_key: ID! password: String! } input ResetPasswordInput { email: String! } input UserChangePasswordInput { """Password in plain text""" existing_password: String new_password: String! reset_key: ID } input UserDestroyInput { id: ID! } input GrantInviteInput { user_id: ID! amount: Int! } input RevokeInviteInput { user_id: ID! amount: Int! } type QueryUsersResultType { count: Int! users: [User!]! } input RoleCriterionInput { value: [RoleEnum!]! modifier: CriterionModifier! } input UserQueryInput { """Filter to search user name - assumes like query unless quoted""" name: String """Filter to search email - assumes like query unless quoted""" email: String """Filter by roles""" roles: RoleCriterionInput """Filter by api key""" apiKey: String """Filter by successful edits""" successful_edits: IntCriterionInput """Filter by unsuccessful edits""" unsuccessful_edits: IntCriterionInput """Filter by votes on successful edits""" successful_votes: IntCriterionInput """Filter by votes on unsuccessful edits""" unsuccessful_votes: IntCriterionInput """Filter by number of API calls""" api_calls: IntCriterionInput """Filter by user that invited""" invited_by: ID page: Int! = 1 per_page: Int! = 25 } type UserEditCount { accepted: Int! rejected: Int! pending: Int! immediate_accepted: Int! immediate_rejected: Int! failed: Int! canceled: Int! } type UserVoteCount { abstain: Int! accept: Int! reject: Int! immediate_accept: Int! immediate_reject: Int! } input GenerateInviteCodeInput { # the number of invite keys to generate. If not set, a single invite key will be generated keys: Int # the number of uses for each invite key. If not set, the invite key will have one use uses: Int # the number of seconds until the invite code expires. If not set, the invite code will never expire ttl: Int } input UserChangeEmailInput { existing_email_token: ID new_email_token: ID new_email: String } enum UserChangeEmailStatus { CONFIRM_OLD CONFIRM_NEW EXPIRED INVALID_TOKEN SUCCESS ERROR } ================================================ FILE: graphql/schema/types/version.graphql ================================================ type Version { hash: String! build_time: String! build_type: String! version: String! } ================================================ FILE: internal/api/context_keys.go ================================================ package api // https://stackoverflow.com/questions/40891345/fix-should-not-use-basic-type-string-as-key-in-context-withvalue-golint type key int const ( ContextRepo key = iota ) ================================================ FILE: internal/api/directives.go ================================================ package api import ( "context" "github.com/99designs/gqlgen/graphql" "github.com/stashapp/stash-box/internal/auth" "github.com/stashapp/stash-box/internal/models" ) func IsUserOwnerDirective(ctx context.Context, obj interface{}, next graphql.Resolver) (interface{}, error) { if err := auth.ValidateUserOrAdmin(ctx, obj.(*models.User).ID); err != nil { return nil, err } return next(ctx) } func HasRoleDirective(ctx context.Context, obj interface{}, next graphql.Resolver, role models.RoleEnum) (interface{}, error) { if err := auth.ValidateRole(ctx, role); err != nil { return nil, err } return next(ctx) } ================================================ FILE: internal/api/draft_integration_test.go ================================================ //go:build integration package api_test import ( "testing" "github.com/stashapp/stash-box/internal/models" "github.com/stretchr/testify/assert" ) type draftTestRunner struct { testRunner } func createDraftTestRunner(t *testing.T) *draftTestRunner { return &draftTestRunner{ testRunner: *asEdit(t), } } func (s *draftTestRunner) testSubmitSceneDraft() { title := "Test Scene Draft" hash := models.FingerprintHash(0xabc123def456) algorithm := models.FingerprintAlgorithmPhash duration := 180 input := models.SceneDraftInput{ Title: &title, Fingerprints: []models.FingerprintInput{ { Hash: hash, Algorithm: algorithm, Duration: duration, }, }, Performers: []models.DraftEntityInput{ { Name: "Test Performer", }, }, } result, err := s.client.submitSceneDraft(input) assert.NoError(s.t, err, "Error submitting scene draft") assert.NotNil(s.t, result, "Result should not be nil") assert.NotNil(s.t, result.ID, "Draft ID should not be nil") assert.NotNil(s.t, result.UUID(), "Draft UUID should not be nil") } func (s *draftTestRunner) testSubmitPerformerDraft() { name := "Test Performer Draft" gender := "Female" country := "US" input := models.PerformerDraftInput{ Name: name, Gender: &gender, Country: &country, } result, err := s.client.submitPerformerDraft(input) assert.NoError(s.t, err, "Error submitting performer draft") assert.NotNil(s.t, result, "Result should not be nil") assert.NotNil(s.t, result.ID, "Draft ID should not be nil") assert.NotNil(s.t, result.UUID(), "Draft UUID should not be nil") } func (s *draftTestRunner) testFindDraft() { // Create a draft first name := "Test Performer for Find" input := models.PerformerDraftInput{ Name: name, } result, err := s.client.submitPerformerDraft(input) assert.NoError(s.t, err, "Error submitting performer draft") assert.NotNil(s.t, result.UUID(), "Draft UUID should not be nil") draftID := *result.UUID() // Find the draft foundDraft, err := s.client.findDraft(draftID) assert.NoError(s.t, err, "Error finding draft") assert.NotNil(s.t, foundDraft, "Found draft should not be nil") assert.Equal(s.t, draftID.String(), foundDraft.ID, "Draft ID should match") } func (s *draftTestRunner) testFindDrafts() { // Create multiple drafts name1 := "Test Performer 1" input1 := models.PerformerDraftInput{ Name: name1, } result1, err := s.client.submitPerformerDraft(input1) assert.NoError(s.t, err, "Error submitting first performer draft") name2 := "Test Performer 2" input2 := models.PerformerDraftInput{ Name: name2, } result2, err := s.client.submitPerformerDraft(input2) assert.NoError(s.t, err, "Error submitting second performer draft") // Find all drafts drafts, err := s.client.findDrafts() assert.NoError(s.t, err, "Error finding drafts") assert.NotNil(s.t, drafts, "Drafts should not be nil") assert.True(s.t, len(drafts) >= 2, "Should have at least 2 drafts") // Verify our created drafts are in the results foundDraft1 := false foundDraft2 := false for _, draft := range drafts { if draft.ID == result1.UUID().String() { foundDraft1 = true } if draft.ID == result2.UUID().String() { foundDraft2 = true } } assert.True(s.t, foundDraft1, "First draft should be found") assert.True(s.t, foundDraft2, "Second draft should be found") } func (s *draftTestRunner) testDestroyDraft() { // Create a draft first name := "Test Performer for Destroy" input := models.PerformerDraftInput{ Name: name, } result, err := s.client.submitPerformerDraft(input) assert.NoError(s.t, err, "Error submitting performer draft") assert.NotNil(s.t, result.UUID(), "Draft UUID should not be nil") draftID := *result.UUID() // Destroy the draft destroyed, err := s.client.destroyDraft(draftID) assert.NoError(s.t, err, "Error destroying draft") assert.True(s.t, destroyed, "Draft should be destroyed") // Verify draft is no longer found foundDraft, err := s.client.findDraft(draftID) // Should return an error since the draft doesn't exist assert.NotNil(s.t, err, "Should return error when finding destroyed draft") assert.Nil(s.t, foundDraft, "Found draft should be nil after destruction") } func TestSubmitSceneDraft(t *testing.T) { pt := createDraftTestRunner(t) pt.testSubmitSceneDraft() } func TestSubmitPerformerDraft(t *testing.T) { pt := createDraftTestRunner(t) pt.testSubmitPerformerDraft() } func TestFindDraft(t *testing.T) { pt := createDraftTestRunner(t) pt.testFindDraft() } func TestFindDrafts(t *testing.T) { pt := createDraftTestRunner(t) pt.testFindDrafts() } func TestDestroyDraft(t *testing.T) { pt := createDraftTestRunner(t) pt.testDestroyDraft() } func (s *draftTestRunner) testSceneDraftTagResolution() { // Create three unique tags using the resolver directly tag1Name := "Tag One" tag1Input := models.TagCreateInput{Name: tag1Name} tag1, err := s.resolver.Mutation().TagCreate(s.ctx, tag1Input) assert.NoError(s.t, err, "Error creating tag 1") tag1ID := tag1.ID tag2Name := "Tag Two" tag2Input := models.TagCreateInput{Name: tag2Name} tag2, err := s.resolver.Mutation().TagCreate(s.ctx, tag2Input) assert.NoError(s.t, err, "Error creating tag 2") tag2ID := tag2.ID tag3Name := "Tag Three" tag3Alias := "Tag Three Alias" tag3Input := models.TagCreateInput{Name: tag3Name, Aliases: []string{tag3Alias}} tag3, err := s.resolver.Mutation().TagCreate(s.ctx, tag3Input) assert.NoError(s.t, err, "Error creating tag 3") tag3ID := tag3.ID // Submit a draft testing all resolution methods title := "Scene with Multiple Tags" hash := models.FingerprintHash(0x1234567890) algorithm := models.FingerprintAlgorithmPhash duration := 120 unmatchedTagName := "Nonexistent Tag" draftInput := models.SceneDraftInput{ Title: &title, Fingerprints: []models.FingerprintInput{ {Hash: hash, Algorithm: algorithm, Duration: duration}, }, Performers: []models.DraftEntityInput{}, Tags: []models.DraftEntityInput{ {Name: tag1Name}, // Test: exact name match {Name: "Ignored", ID: &tag2ID}, // Test: ID match (name ignored) {Name: tag3Alias}, // Test: alias match {Name: unmatchedTagName}, // Test: non-existent tag }, } draft, err := s.client.submitSceneDraft(draftInput) assert.NoError(s.t, err, "Error submitting draft") assert.NotNil(s.t, draft.UUID(), "Draft UUID should not be nil") // Query back and verify all tags foundDraft, err := s.client.findDraftWithTags(*draft.UUID()) assert.NoError(s.t, err, "Error finding draft") assert.NotNil(s.t, foundDraft.Data, "Draft data should not be nil") draftData := foundDraft.Data.(map[string]interface{}) tags, ok := draftData["tags"].([]interface{}) assert.True(s.t, ok, "Tags should be an array") assert.Equal(s.t, 4, len(tags), "Should have exactly 4 tags") // Verify each tag tag1Found := tags[0].(map[string]interface{}) assert.Equal(s.t, "Tag", tag1Found["__typename"], "Tag 1 should be resolved") assert.Equal(s.t, tag1ID.String(), tag1Found["id"], "Tag 1 ID should match") assert.Equal(s.t, tag1Name, tag1Found["name"], "Tag 1 name should match") tag2Found := tags[1].(map[string]interface{}) assert.Equal(s.t, "Tag", tag2Found["__typename"], "Tag 2 should be resolved") assert.Equal(s.t, tag2ID.String(), tag2Found["id"], "Tag 2 ID should match") assert.Equal(s.t, tag2Name, tag2Found["name"], "Tag 2 name should match") tag3Found := tags[2].(map[string]interface{}) assert.Equal(s.t, "Tag", tag3Found["__typename"], "Tag 3 should be resolved") assert.Equal(s.t, tag3ID.String(), tag3Found["id"], "Tag 3 ID should match") assert.Equal(s.t, tag3Name, tag3Found["name"], "Tag 3 name should match") unmatchedFound := tags[3].(map[string]interface{}) assert.Equal(s.t, "DraftEntity", unmatchedFound["__typename"], "Unmatched tag should be DraftEntity") assert.Equal(s.t, unmatchedTagName, unmatchedFound["name"], "Unmatched tag name should match") } func TestSceneDraftTagResolution(t *testing.T) { pt := createDraftTestRunner(t) pt.testSceneDraftTagResolution() } ================================================ FILE: internal/api/edit_amend_integration_test.go ================================================ //go:build integration package api_test import ( "testing" "github.com/stashapp/stash-box/internal/models" "github.com/stretchr/testify/assert" ) type editAmendTestRunner struct { testRunner } func createEditAmendTestRunner(t *testing.T) *editAmendTestRunner { return &editAmendTestRunner{ testRunner: *asModerate(t), } } func (s *editAmendTestRunner) testAmendClosedEdit() { // Create a performer edit with name and aliases name := s.generatePerformerName() aliases := []string{"Alias1", "Alias2"} detailsInput := &models.PerformerEditDetailsInput{ Name: &name, Aliases: aliases, } createdEdit, err := s.createTestPerformerEdit(models.OperationEnumCreate, detailsInput, nil, nil) assert.NoError(s.t, err) // Apply the edit to make it closed (requires admin) adminRunner := asAdmin(s.t) appliedEdit, err := adminRunner.applyEdit(createdEdit.ID) assert.NoError(s.t, err) assert.NotNil(s.t, appliedEdit.ClosedAt) // Amend the edit - remove the name field reason := "Removing incorrect name" amendInput := models.AmendEditInput{ ID: appliedEdit.ID, Reason: reason, RemoveFields: []string{"name"}, } amendedEdit, err := s.resolver.Mutation().AmendEdit(s.ctx, amendInput) assert.NoError(s.t, err) assert.NotNil(s.t, amendedEdit) // Verify the edit still exists and can be fetched edit, err := s.resolver.Query().FindEdit(s.ctx, appliedEdit.ID) assert.NoError(s.t, err) assert.NotNil(s.t, edit) } func (s *editAmendTestRunner) testAmendArrayItems() { // Create a performer edit with multiple aliases name := s.generatePerformerName() aliases := []string{"Alias1", "Alias2", "Alias3"} detailsInput := &models.PerformerEditDetailsInput{ Name: &name, Aliases: aliases, } createdEdit, err := s.createTestPerformerEdit(models.OperationEnumCreate, detailsInput, nil, nil) assert.NoError(s.t, err) // Apply the edit adminRunner := asAdmin(s.t) appliedEdit, err := adminRunner.applyEdit(createdEdit.ID) assert.NoError(s.t, err) assert.NotNil(s.t, appliedEdit.ClosedAt) // Amend the edit - remove one alias reason := "Removing incorrect alias" amendInput := models.AmendEditInput{ ID: appliedEdit.ID, Reason: reason, RemoveAddedItems: []models.AmendItemRemoval{ { Field: "aliases", Indices: []int{1}, // Remove "Alias2" }, }, } amendedEdit, err := s.resolver.Mutation().AmendEdit(s.ctx, amendInput) assert.NoError(s.t, err) assert.NotNil(s.t, amendedEdit) } func (s *editAmendTestRunner) testCannotAmendPendingEdit() { // Create a performer edit (leave it pending) createdEdit, err := s.createTestPerformerEdit(models.OperationEnumCreate, nil, nil, nil) assert.NoError(s.t, err) assert.Nil(s.t, createdEdit.ClosedAt) assert.Equal(s.t, models.VoteStatusEnumPending.String(), createdEdit.Status) // Attempt to amend pending edit reason := "Test reason" amendInput := models.AmendEditInput{ ID: createdEdit.ID, Reason: reason, RemoveFields: []string{"name"}, } _, err = s.resolver.Mutation().AmendEdit(s.ctx, amendInput) assert.Error(s.t, err) assert.Contains(s.t, err.Error(), "cannot amend pending edit") } func (s *editAmendTestRunner) testNonModeratorCannotAmend() { // Create and close an edit as moderator createdEdit, err := s.createTestPerformerEdit(models.OperationEnumCreate, nil, nil, nil) assert.NoError(s.t, err) adminRunner := asAdmin(s.t) appliedEdit, err := adminRunner.applyEdit(createdEdit.ID) assert.NoError(s.t, err) assert.NotNil(s.t, appliedEdit.ClosedAt) // Switch to non-moderator user (edit role only) editRunner := asEdit(s.t) reason := "Test reason" amendInput := models.AmendEditInput{ ID: appliedEdit.ID, Reason: reason, RemoveFields: []string{"name"}, } // Attempt to amend as non-moderator (using client to enforce directives) _, err = editRunner.client.amendEdit(amendInput) assert.Error(s.t, err) assert.Contains(s.t, err.Error(), "not authorized") } func (s *editAmendTestRunner) testAmendRequiresReason() { // Create and close an edit with multiple fields name := s.generatePerformerName() aliases := []string{"Alias1", "Alias2"} detailsInput := &models.PerformerEditDetailsInput{ Name: &name, Aliases: aliases, } createdEdit, err := s.createTestPerformerEdit(models.OperationEnumCreate, detailsInput, nil, nil) assert.NoError(s.t, err) adminRunner := asAdmin(s.t) appliedEdit, err := adminRunner.applyEdit(createdEdit.ID) assert.NoError(s.t, err) // Attempt to amend with empty reason - should still work as the reason is just metadata // The validation is for having at least one removal amendInput := models.AmendEditInput{ ID: appliedEdit.ID, Reason: "", // Empty reason RemoveFields: []string{"name"}, } // Empty reason is allowed at the backend level - the frontend enforces required _, err = s.resolver.Mutation().AmendEdit(s.ctx, amendInput) assert.NoError(s.t, err) } func (s *editAmendTestRunner) testAmendRequiresChanges() { // Create and close an edit createdEdit, err := s.createTestPerformerEdit(models.OperationEnumCreate, nil, nil, nil) assert.NoError(s.t, err) adminRunner := asAdmin(s.t) appliedEdit, err := adminRunner.applyEdit(createdEdit.ID) assert.NoError(s.t, err) // Attempt to amend without specifying any removals amendInput := models.AmendEditInput{ ID: appliedEdit.ID, Reason: "Some reason", // No RemoveFields, RemoveAddedItems, or RemoveRemovedItems } _, err = s.resolver.Mutation().AmendEdit(s.ctx, amendInput) assert.Error(s.t, err) assert.Contains(s.t, err.Error(), "must specify at least one field or item to remove") } func TestAmendClosedEdit(t *testing.T) { s := createEditAmendTestRunner(t) s.testAmendClosedEdit() } func TestAmendArrayItems(t *testing.T) { s := createEditAmendTestRunner(t) s.testAmendArrayItems() } func TestCannotAmendPendingEdit(t *testing.T) { s := createEditAmendTestRunner(t) s.testCannotAmendPendingEdit() } func TestNonModeratorCannotAmendEdit(t *testing.T) { s := createEditAmendTestRunner(t) s.testNonModeratorCannotAmend() } func TestAmendRequiresReason(t *testing.T) { s := createEditAmendTestRunner(t) s.testAmendRequiresReason() } func TestAmendRequiresChanges(t *testing.T) { s := createEditAmendTestRunner(t) s.testAmendRequiresChanges() } ================================================ FILE: internal/api/edit_delete_integration_test.go ================================================ //go:build integration package api_test import ( "testing" "github.com/stashapp/stash-box/internal/models" "github.com/stretchr/testify/assert" ) type editDeleteTestRunner struct { testRunner } func createEditDeleteTestRunner(t *testing.T) *editDeleteTestRunner { return &editDeleteTestRunner{ testRunner: *asModerate(t), } } func (s *editDeleteTestRunner) testDeleteClosedEdit() { // Create a tag edit createdEdit, err := s.createTestTagEdit(models.OperationEnumCreate, nil, nil) assert.NoError(s.t, err) // Apply the edit to make it closed (requires admin) adminRunner := asAdmin(s.t) appliedEdit, err := adminRunner.applyEdit(createdEdit.ID) assert.NoError(s.t, err) assert.NotNil(s.t, appliedEdit.ClosedAt) assert.Equal(s.t, models.VoteStatusEnumImmediateAccepted.String(), appliedEdit.Status) // Delete the closed edit reason := "Test deletion reason" deleteInput := models.DeleteEditInput{ ID: appliedEdit.ID, Reason: reason, } deleted, err := s.resolver.Mutation().DeleteEdit(s.ctx, deleteInput) assert.NoError(s.t, err) assert.True(s.t, deleted) // Verify edit is deleted - should return nil edit, err := s.resolver.Query().FindEdit(s.ctx, appliedEdit.ID) assert.NoError(s.t, err) assert.Nil(s.t, edit) // Note: Cannot easily verify audit record in test due to transaction isolation // The audit record is created in the service layer and would require direct database access } func (s *editDeleteTestRunner) testCannotDeletePendingEdit() { // Create a tag edit (leave it pending) createdEdit, err := s.createTestTagEdit(models.OperationEnumCreate, nil, nil) assert.NoError(s.t, err) assert.Nil(s.t, createdEdit.ClosedAt) assert.Equal(s.t, models.VoteStatusEnumPending.String(), createdEdit.Status) // Attempt to delete pending edit reason := "Test reason" deleteInput := models.DeleteEditInput{ ID: createdEdit.ID, Reason: reason, } deleted, err := s.resolver.Mutation().DeleteEdit(s.ctx, deleteInput) assert.Error(s.t, err) assert.False(s.t, deleted) assert.Contains(s.t, err.Error(), "cannot delete pending edit") // Verify edit still exists edit, err := s.resolver.Query().FindEdit(s.ctx, createdEdit.ID) assert.NoError(s.t, err) assert.NotNil(s.t, edit) assert.Equal(s.t, createdEdit.ID, edit.ID) } func (s *editDeleteTestRunner) testNonModeratorCannotDelete() { // Create and close an edit as moderator createdEdit, err := s.createTestTagEdit(models.OperationEnumCreate, nil, nil) assert.NoError(s.t, err) adminRunner := asAdmin(s.t) appliedEdit, err := adminRunner.applyEdit(createdEdit.ID) assert.NoError(s.t, err) assert.NotNil(s.t, appliedEdit.ClosedAt) // Switch to non-moderator user (edit role only) editRunner := asEdit(s.t) reason := "Test reason" deleteInput := models.DeleteEditInput{ ID: appliedEdit.ID, Reason: reason, } // Attempt to delete as non-moderator (using client to enforce directives) deleted, err := editRunner.client.deleteEdit(deleteInput) assert.Error(s.t, err) assert.False(s.t, deleted) assert.Contains(s.t, err.Error(), "not authorized") // Verify edit still exists edit, err := s.resolver.Query().FindEdit(s.ctx, appliedEdit.ID) assert.NoError(s.t, err) assert.NotNil(s.t, edit) assert.Equal(s.t, appliedEdit.ID, edit.ID) } func (s *editDeleteTestRunner) testDeleteRejectedEdit() { // Create a tag edit createdEdit, err := s.createTestTagEdit(models.OperationEnumCreate, nil, nil) assert.NoError(s.t, err) // Cancel/reject the edit cancelInput := models.CancelEditInput{ ID: createdEdit.ID, } canceledEdit, err := s.resolver.Mutation().CancelEdit(s.ctx, cancelInput) assert.NoError(s.t, err) assert.NotNil(s.t, canceledEdit.ClosedAt) assert.Equal(s.t, models.VoteStatusEnumCanceled.String(), canceledEdit.Status) // Delete the rejected edit reason := "Removing rejected edit" deleteInput := models.DeleteEditInput{ ID: canceledEdit.ID, Reason: reason, } deleted, err := s.resolver.Mutation().DeleteEdit(s.ctx, deleteInput) assert.NoError(s.t, err) assert.True(s.t, deleted) // Verify edit is deleted edit, err := s.resolver.Query().FindEdit(s.ctx, canceledEdit.ID) assert.NoError(s.t, err) assert.Nil(s.t, edit) } func (s *editDeleteTestRunner) testDeleteEditWithComments() { // Create a tag edit createdEdit, err := s.createTestTagEdit(models.OperationEnumCreate, nil, nil) assert.NoError(s.t, err) // Add a comment commentText := "Test comment" commentInput := models.EditCommentInput{ ID: createdEdit.ID, Comment: commentText, } _, err = s.resolver.Mutation().EditComment(s.ctx, commentInput) assert.NoError(s.t, err) // Verify comment exists comments, err := s.resolver.Edit().Comments(s.ctx, createdEdit) assert.NoError(s.t, err) assert.Equal(s.t, 1, len(comments)) // Close the edit (requires admin) adminRunner := asAdmin(s.t) appliedEdit, err := adminRunner.applyEdit(createdEdit.ID) assert.NoError(s.t, err) // Delete the edit reason := "Cleaning up test edit with comments" deleteInput := models.DeleteEditInput{ ID: appliedEdit.ID, Reason: reason, } deleted, err := s.resolver.Mutation().DeleteEdit(s.ctx, deleteInput) assert.NoError(s.t, err) assert.True(s.t, deleted) // Verify edit and comments are deleted (CASCADE) edit, err := s.resolver.Query().FindEdit(s.ctx, appliedEdit.ID) assert.NoError(s.t, err) assert.Nil(s.t, edit) } func (s *editDeleteTestRunner) testDeleteEditWithVotes() { // Create a tag edit as non-admin editRunner := asEdit(s.t) createdEdit, err := editRunner.createTestTagEdit(models.OperationEnumCreate, nil, nil) assert.NoError(s.t, err) // Vote on it as admin voteInput := models.EditVoteInput{ ID: createdEdit.ID, Vote: models.VoteTypeEnumAccept, } _, err = s.resolver.Mutation().EditVote(s.ctx, voteInput) assert.NoError(s.t, err) // Verify vote exists votes, err := s.resolver.Edit().Votes(s.ctx, createdEdit) assert.NoError(s.t, err) assert.Equal(s.t, 1, len(votes)) // Close the edit (requires admin) adminRunner := asAdmin(s.t) appliedEdit, err := adminRunner.applyEdit(createdEdit.ID) assert.NoError(s.t, err) // Delete the edit reason := "Cleaning up test edit with votes" deleteInput := models.DeleteEditInput{ ID: appliedEdit.ID, Reason: reason, } deleted, err := s.resolver.Mutation().DeleteEdit(s.ctx, deleteInput) assert.NoError(s.t, err) assert.True(s.t, deleted) // Verify edit and votes are deleted (CASCADE) edit, err := s.resolver.Query().FindEdit(s.ctx, appliedEdit.ID) assert.NoError(s.t, err) assert.Nil(s.t, edit) } func TestDeleteClosedEdit(t *testing.T) { s := createEditDeleteTestRunner(t) s.testDeleteClosedEdit() } func TestCannotDeletePendingEdit(t *testing.T) { s := createEditDeleteTestRunner(t) s.testCannotDeletePendingEdit() } func TestNonModeratorCannotDeleteEdit(t *testing.T) { s := createEditDeleteTestRunner(t) s.testNonModeratorCannotDelete() } func TestDeleteRejectedEdit(t *testing.T) { s := createEditDeleteTestRunner(t) s.testDeleteRejectedEdit() } func TestDeleteEditWithComments(t *testing.T) { s := createEditDeleteTestRunner(t) s.testDeleteEditWithComments() } func TestDeleteEditWithVotes(t *testing.T) { s := createEditDeleteTestRunner(t) s.testDeleteEditWithVotes() } ================================================ FILE: internal/api/edit_integration_test.go ================================================ //go:build integration package api_test import ( "context" "testing" "time" "github.com/stashapp/stash-box/internal/auth" "github.com/stashapp/stash-box/internal/models" "github.com/stretchr/testify/assert" ) type editTestRunner struct { testRunner } func createEditTestRunner(t *testing.T) *editTestRunner { return &editTestRunner{ testRunner: *asAdmin(t), } } func (s *editTestRunner) testAdminCancelEdit() { createdEdit, err := s.createTestTagEdit(models.OperationEnumCreate, nil, nil) assert.NoError(s.t, err) editInput := models.CancelEditInput{ ID: createdEdit.ID, } pt := createEditTestRunner(s.t) cancelEdit, err := s.resolver.Mutation().CancelEdit(pt.ctx, editInput) assert.NoError(s.t, err, "Admin failed to cancel edit: %s") s.verifyAdminCancelEdit(cancelEdit) } func (s *editTestRunner) verifyAdminCancelEdit(edit *models.Edit) { s.verifyEditOperation(models.OperationEnumCreate.String(), edit) s.verifyEditStatus(models.VoteStatusEnumImmediateRejected.String(), edit) s.verifyEditTargetType(models.TargetTypeEnumTag.String(), edit) s.verifyEditApplication(false, edit) } func (s *editTestRunner) testOwnerCancelEdit() { createdEdit, err := s.createTestTagEdit(models.OperationEnumCreate, nil, nil) assert.NoError(s.t, err) editInput := models.CancelEditInput{ ID: createdEdit.ID, } cancelEdit, err := s.resolver.Mutation().CancelEdit(s.ctx, editInput) assert.NoError(s.t, err) s.verifyOwnerCancelEdit(cancelEdit) } func (s *editTestRunner) verifyOwnerCancelEdit(edit *models.Edit) { s.verifyEditOperation(models.OperationEnumCreate.String(), edit) s.verifyEditStatus(models.VoteStatusEnumCanceled.String(), edit) s.verifyEditTargetType(models.TargetTypeEnumTag.String(), edit) s.verifyEditApplication(false, edit) } func (s *editTestRunner) testEditComment() { createdEdit, err := s.createTestTagEdit(models.OperationEnumCreate, nil, nil) assert.NoError(s.t, err) text := "some comment text" editInput := models.EditCommentInput{ ID: createdEdit.ID, Comment: text, } editComment, err := s.resolver.Mutation().EditComment(s.ctx, editInput) assert.NoError(s.t, err) s.verifyEditComment(editComment, text) } func (s *editTestRunner) verifyEditComment(edit *models.Edit, comment string) { comments, _ := s.resolver.Edit().Comments(s.ctx, edit) assert.True(s.t, len(comments) == 1) assert.Equal(s.t, comments[0].Text, comment) } func (s *editTestRunner) testVotePermissionsPromotion() { createdUser, err := s.createTestUser(nil, []models.RoleEnum{models.RoleEnumEdit}) assert.NoError(s.t, err) for i := 1; i <= 10; i++ { s.ctx = context.WithValue(s.ctx, auth.ContextUser, createdUser) createdEdit, err := s.createTestTagEdit(models.OperationEnumCreate, nil, nil) assert.NoError(s.t, err) s.ctx = context.WithValue(s.ctx, auth.ContextRoles, userDB.adminRoles) _, err = s.applyEdit(createdEdit.ID) assert.NoError(s.t, err) } s.ctx = context.WithValue(s.ctx, auth.ContextUser, createdUser) // Wait for async promotion to complete time.Sleep(50 * time.Millisecond) userID := createdUser.ID user, err := s.resolver.Query().FindUser(s.ctx, &userID, nil) assert.NoError(s.t, err) s.verifyUserRolePromotion(user) } func (s *editTestRunner) verifyUserRolePromotion(user *models.User) { roles, _ := s.resolver.User().Roles(s.ctx, user) hasVotePermission := false for _, role := range roles { if role == models.RoleEnumVote { hasVotePermission = true } } assert.Equal(s.t, hasVotePermission, true) } func (s *editTestRunner) testPositiveEditVoteApplication() { createdEdit, err := s.createTestTagEdit(models.OperationEnumCreate, nil, nil) assert.NoError(s.t, err) for i := 1; i <= 3; i++ { createdUser, err := s.createTestUser(nil, []models.RoleEnum{models.RoleEnumVote}) assert.NoError(s.t, err) s.ctx = context.WithValue(s.ctx, auth.ContextUser, createdUser) votedEdit, err := s.resolver.Mutation().EditVote(s.ctx, models.EditVoteInput{ ID: createdEdit.ID, Vote: models.VoteTypeEnumAccept, }) assert.NoError(s.t, err) // Verify vote_count is updated correctly after each vote if i < 3 { // First two votes should not trigger auto-apply assert.Equal(s.t, i, votedEdit.VoteCount, "Vote count should be %d after %d accept votes", i, i) } } updatedEdit, err := s.resolver.Query().FindEdit(s.ctx, createdEdit.ID) assert.NoError(s.t, err) s.verifyEditApplied(updatedEdit) } func (s *editTestRunner) verifyEditApplied(edit *models.Edit) { s.verifyEditStatus(models.VoteStatusEnumAccepted.String(), edit) } func (s *editTestRunner) verifyEditRejected(edit *models.Edit) { s.verifyEditStatus(models.VoteStatusEnumRejected.String(), edit) } func (s *editTestRunner) testNegativeEditVoteApplication() { createdEdit, err := s.createTestTagEdit(models.OperationEnumCreate, nil, nil) assert.NoError(s.t, err) for i := 1; i <= 3; i++ { createdUser, err := s.createTestUser(nil, []models.RoleEnum{models.RoleEnumVote}) assert.NoError(s.t, err) s.ctx = context.WithValue(s.ctx, auth.ContextUser, createdUser) votedEdit, err := s.resolver.Mutation().EditVote(s.ctx, models.EditVoteInput{ ID: createdEdit.ID, Vote: models.VoteTypeEnumReject, }) assert.NoError(s.t, err) // Verify vote_count is updated correctly after each vote if i < 3 { // First two votes should not trigger auto-reject assert.Equal(s.t, -i, votedEdit.VoteCount, "Vote count should be -%d after %d reject votes", i, i) } } updatedEdit, err := s.resolver.Query().FindEdit(s.ctx, createdEdit.ID) assert.NoError(s.t, err) s.verifyEditRejected(updatedEdit) } func (s *editTestRunner) testEditVoteNotApplying() { createdEdit, err := s.createTestTagEdit(models.OperationEnumCreate, nil, nil) assert.NoError(s.t, err) for i := 1; i <= 3; i++ { createdUser, err := s.createTestUser(nil, []models.RoleEnum{models.RoleEnumVote}) assert.NoError(s.t, err) s.ctx = context.WithValue(s.ctx, auth.ContextUser, createdUser) vote := models.VoteTypeEnumAccept if i == 3 { vote = models.VoteTypeEnumReject } votedEdit, err := s.resolver.Mutation().EditVote(s.ctx, models.EditVoteInput{ ID: createdEdit.ID, Vote: vote, }) assert.NoError(s.t, err) // Verify vote_count is updated correctly after each vote expectedCount := i if i == 3 { // After 2 accepts and 1 reject: 2 - 1 = 1 expectedCount = 1 } assert.Equal(s.t, expectedCount, votedEdit.VoteCount, "Vote count should be %d after vote %d", expectedCount, i) } updatedEdit, err := s.resolver.Query().FindEdit(s.ctx, createdEdit.ID) assert.NoError(s.t, err) s.verifyEditPending(updatedEdit) // Final verification of vote_count assert.Equal(s.t, 1, updatedEdit.VoteCount, "Final vote count should be 1 (2 accepts - 1 reject)") } func (s *editTestRunner) verifyEditPending(edit *models.Edit) { s.verifyEditStatus(models.VoteStatusEnumPending.String(), edit) } func (s *editTestRunner) testDestructiveEditsNotAutoApplied() { createdTag, err := s.createTestTag(nil) assert.NoError(s.t, err) id := createdTag.UUID() input := models.EditInput{ ID: &id, Operation: models.OperationEnumDestroy, } createdEdit, err := s.createTestTagEdit(models.OperationEnumDestroy, nil, &input) assert.NoError(s.t, err) for i := 1; i <= 3; i++ { createdUser, err := s.createTestUser(nil, []models.RoleEnum{models.RoleEnumVote}) assert.NoError(s.t, err) s.ctx = context.WithValue(s.ctx, auth.ContextUser, createdUser) s.resolver.Mutation().EditVote(s.ctx, models.EditVoteInput{ ID: createdEdit.ID, Vote: models.VoteTypeEnumAccept, }) } updatedEdit, err := s.resolver.Query().FindEdit(s.ctx, createdEdit.ID) assert.NoError(s.t, err) s.verifyEditPending(updatedEdit) } func (s *editTestRunner) testVoteOwnedEditsDisallowed() { createdEdit, err := s.createTestTagEdit(models.OperationEnumCreate, nil, nil) assert.NoError(s.t, err) _, err = s.resolver.Mutation().EditVote(s.ctx, models.EditVoteInput{ ID: createdEdit.ID, Vote: models.VoteTypeEnumAccept, }) assert.ErrorIs(s.t, err, auth.ErrUnauthorized) } func TestAdminCancelEdit(t *testing.T) { pt := &editTestRunner{ testRunner: *asEdit(t), } pt.testAdminCancelEdit() } func TestOwnerCancelEdit(t *testing.T) { pt := &editTestRunner{ testRunner: *asEdit(t), } pt.testOwnerCancelEdit() } func TestEditComment(t *testing.T) { pt := createEditTestRunner(t) pt.testEditComment() } func TestVotePermissionsPromotion(t *testing.T) { pt := createEditTestRunner(t) pt.testVotePermissionsPromotion() } func TestPositiveEditVoteApplication(t *testing.T) { pt := createEditTestRunner(t) pt.testPositiveEditVoteApplication() } func TestNegativeEditVoteApplication(t *testing.T) { pt := createEditTestRunner(t) pt.testNegativeEditVoteApplication() } func TestEditVoteNotApplying(t *testing.T) { pt := createEditTestRunner(t) pt.testEditVoteNotApplying() } func TestDestructiveEditsNotAutoApplied(t *testing.T) { pt := createEditTestRunner(t) pt.testDestructiveEditsNotAutoApplied() } func TestVoteOwnedEditsDisallowed(t *testing.T) { pt := createEditTestRunner(t) pt.testVoteOwnedEditsDisallowed() } func (s *editTestRunner) testQueryEdits() { // Create test data: different types of edits with different statuses // Create pending performer edit _, err := s.createTestPerformerEdit(models.OperationEnumCreate, nil, nil, nil) assert.NoError(s.t, err) // Create pending scene edit _, err = s.createTestSceneEdit(models.OperationEnumCreate, nil, nil) assert.NoError(s.t, err) // Create pending studio edit studioEdit1, err := s.createTestStudioEdit(models.OperationEnumCreate, nil, nil) assert.NoError(s.t, err) // Create pending tag edit tagEdit1, err := s.createTestTagEdit(models.OperationEnumCreate, nil, nil) assert.NoError(s.t, err) // Create a modify edit for an existing performer existingPerformer, err := s.createTestPerformer(nil) assert.NoError(s.t, err) performerID := existingPerformer.UUID() performerModifyEdit, err := s.createTestPerformerEdit(models.OperationEnumModify, nil, &models.EditInput{ Operation: models.OperationEnumModify, ID: &performerID, }, nil) assert.NoError(s.t, err) // Apply one edit to have an applied edit appliedEdit, err := s.applyEdit(tagEdit1.ID) assert.NoError(s.t, err) // Cancel one edit to have a cancelled edit _, err = s.resolver.Mutation().CancelEdit(s.ctx, models.CancelEditInput{ ID: studioEdit1.ID, }) assert.NoError(s.t, err) // Test 1: Query all pending edits result, err := s.resolver.Query().QueryEdits(s.ctx, models.EditQueryInput{ Status: &[]models.VoteStatusEnum{models.VoteStatusEnumPending}[0], Page: 1, PerPage: 25, Direction: models.SortDirectionEnumDesc, Sort: models.EditSortEnumCreatedAt, }) assert.NoError(s.t, err) editsResult, err := s.resolver.QueryEditsResultType().Edits(s.ctx, result) assert.NoError(s.t, err) count, err := s.resolver.QueryEditsResultType().Count(s.ctx, result) assert.NoError(s.t, err) assert.True(s.t, count >= 3, "Should have at least 3 pending edits") assert.True(s.t, len(editsResult) >= 3, "Should return at least 3 pending edits") // Verify all returned edits are pending for _, edit := range editsResult { assert.Equal(s.t, edit.Status, models.VoteStatusEnumPending.String(), "All returned edits should be pending") } // Test 2: Query by target type (PERFORMER) result, err = s.resolver.Query().QueryEdits(s.ctx, models.EditQueryInput{ TargetType: &[]models.TargetTypeEnum{models.TargetTypeEnumPerformer}[0], Page: 1, PerPage: 25, Direction: models.SortDirectionEnumDesc, Sort: models.EditSortEnumCreatedAt, }) assert.NoError(s.t, err) editsResult, err = s.resolver.QueryEditsResultType().Edits(s.ctx, result) assert.NoError(s.t, err) assert.True(s.t, len(editsResult) >= 2, "Should have at least 2 performer edits") for _, edit := range editsResult { assert.Equal(s.t, edit.TargetType, models.TargetTypeEnumPerformer.String(), "All returned edits should be performer type") } // Test 3: Query by operation (CREATE) result, err = s.resolver.Query().QueryEdits(s.ctx, models.EditQueryInput{ Operation: &[]models.OperationEnum{models.OperationEnumCreate}[0], Page: 1, PerPage: 25, Direction: models.SortDirectionEnumDesc, Sort: models.EditSortEnumCreatedAt, }) assert.NoError(s.t, err) editsResult, err = s.resolver.QueryEditsResultType().Edits(s.ctx, result) assert.NoError(s.t, err) assert.True(s.t, len(editsResult) >= 4, "Should have at least 4 create edits") for _, edit := range editsResult { assert.Equal(s.t, edit.Operation, models.OperationEnumCreate.String(), "All returned edits should be CREATE operation") } // Test 4: Query by operation (MODIFY) result, err = s.resolver.Query().QueryEdits(s.ctx, models.EditQueryInput{ Operation: &[]models.OperationEnum{models.OperationEnumModify}[0], Page: 1, PerPage: 25, Direction: models.SortDirectionEnumDesc, Sort: models.EditSortEnumCreatedAt, }) assert.NoError(s.t, err) editsResult, err = s.resolver.QueryEditsResultType().Edits(s.ctx, result) assert.NoError(s.t, err) assert.True(s.t, len(editsResult) >= 1, "Should have at least 1 modify edit") for _, edit := range editsResult { assert.Equal(s.t, edit.Operation, models.OperationEnumModify.String(), "All returned edits should be MODIFY operation") } // Test 5: Query by applied status (applied=true) result, err = s.resolver.Query().QueryEdits(s.ctx, models.EditQueryInput{ Applied: &[]bool{true}[0], Page: 1, PerPage: 25, Direction: models.SortDirectionEnumDesc, Sort: models.EditSortEnumCreatedAt, }) assert.NoError(s.t, err) editsResult, err = s.resolver.QueryEditsResultType().Edits(s.ctx, result) assert.NoError(s.t, err) assert.True(s.t, len(editsResult) >= 1, "Should have at least 1 applied edit") // Verify the applied edit is in the results foundApplied := false for _, edit := range editsResult { assert.Equal(s.t, edit.Applied, true, "All returned edits should be applied") if edit.ID == appliedEdit.ID { foundApplied = true } } assert.True(s.t, foundApplied, "Should find the applied edit we created") // Test 6: Query by applied status (applied=false) result, err = s.resolver.Query().QueryEdits(s.ctx, models.EditQueryInput{ Applied: &[]bool{false}[0], Page: 1, PerPage: 25, Direction: models.SortDirectionEnumDesc, Sort: models.EditSortEnumCreatedAt, }) assert.NoError(s.t, err) editsResult, err = s.resolver.QueryEditsResultType().Edits(s.ctx, result) assert.NoError(s.t, err) assert.True(s.t, len(editsResult) >= 3, "Should have at least 3 unapplied edits") for _, edit := range editsResult { assert.Equal(s.t, edit.Applied, false, "All returned edits should be unapplied") } // Test 7: Query by specific target ID result, err = s.resolver.Query().QueryEdits(s.ctx, models.EditQueryInput{ TargetType: &[]models.TargetTypeEnum{models.TargetTypeEnumPerformer}[0], TargetID: &performerID, Page: 1, PerPage: 25, Direction: models.SortDirectionEnumDesc, Sort: models.EditSortEnumCreatedAt, }) assert.NoError(s.t, err) editsResult, err = s.resolver.QueryEditsResultType().Edits(s.ctx, result) assert.NoError(s.t, err) assert.True(s.t, len(editsResult) >= 1, "Should have at least 1 edit for the target") foundModifyEdit := false for _, edit := range editsResult { if edit.ID == performerModifyEdit.ID { foundModifyEdit = true } } assert.True(s.t, foundModifyEdit, "Should find the modify edit for the specific performer") // Test 8: Query by user ID result, err = s.resolver.Query().QueryEdits(s.ctx, models.EditQueryInput{ UserID: &userDB.admin.ID, Page: 1, PerPage: 25, Direction: models.SortDirectionEnumDesc, Sort: models.EditSortEnumCreatedAt, }) assert.NoError(s.t, err) editsResult, err = s.resolver.QueryEditsResultType().Edits(s.ctx, result) assert.NoError(s.t, err) assert.True(s.t, len(editsResult) >= 4, "Should have at least 4 edits by the current user") for _, edit := range editsResult { user, _ := s.resolver.Edit().User(s.ctx, &edit) assert.Equal(s.t, user.ID, userDB.admin.ID, "All returned edits should be by the specified user") } // Test 9: Test pagination result, err = s.resolver.Query().QueryEdits(s.ctx, models.EditQueryInput{ Page: 1, PerPage: 2, Direction: models.SortDirectionEnumDesc, Sort: models.EditSortEnumCreatedAt, }) assert.NoError(s.t, err) editsResult, err = s.resolver.QueryEditsResultType().Edits(s.ctx, result) assert.NoError(s.t, err) count, err = s.resolver.QueryEditsResultType().Count(s.ctx, result) assert.NoError(s.t, err) assert.Equal(s.t, len(editsResult), 2, "Should return exactly 2 edits with per_page=2") assert.True(s.t, count >= 4, "Total count should be at least 4") // Test 10: Test sorting by CREATED_AT ascending result, err = s.resolver.Query().QueryEdits(s.ctx, models.EditQueryInput{ Status: &[]models.VoteStatusEnum{models.VoteStatusEnumPending}[0], Page: 1, PerPage: 10, Direction: models.SortDirectionEnumAsc, Sort: models.EditSortEnumCreatedAt, }) assert.NoError(s.t, err) editsResult, err = s.resolver.QueryEditsResultType().Edits(s.ctx, result) assert.NoError(s.t, err) if len(editsResult) >= 2 { // Verify ascending order for i := 0; i < len(editsResult)-1; i++ { assert.True(s.t, !editsResult[i].CreatedAt.After(editsResult[i+1].CreatedAt), "Edits should be sorted by created_at in ascending order") } } // Test 11: Query cancelled edits result, err = s.resolver.Query().QueryEdits(s.ctx, models.EditQueryInput{ Status: &[]models.VoteStatusEnum{models.VoteStatusEnumCanceled}[0], Page: 1, PerPage: 25, Direction: models.SortDirectionEnumDesc, Sort: models.EditSortEnumCreatedAt, }) assert.NoError(s.t, err) editsResult, err = s.resolver.QueryEditsResultType().Edits(s.ctx, result) assert.NoError(s.t, err) assert.True(s.t, len(editsResult) >= 1, "Should have at least 1 cancelled edit") for _, edit := range editsResult { assert.Equal(s.t, edit.Status, models.VoteStatusEnumCanceled.String(), "All returned edits should be cancelled") } } func TestQueryEdits(t *testing.T) { pt := createEditTestRunner(t) pt.testQueryEdits() } func (s *editTestRunner) testBotFlag() { // Test creating edit without bot flag (should default to false) normalEdit, err := s.createTestTagEdit(models.OperationEnumCreate, nil, nil) assert.NoError(s.t, err) assert.False(s.t, normalEdit.Bot, "Edit without bot flag should have bot=false") // Test creating edit with bot flag set to true botTrue := true editWithBotTrue, err := s.createTestTagEdit(models.OperationEnumCreate, nil, &models.EditInput{ Operation: models.OperationEnumCreate, Bot: &botTrue, }) assert.NoError(s.t, err) assert.True(s.t, editWithBotTrue.Bot, "Edit with bot=true should have bot=true") // Query for bot edits and verify we get exactly one resultBot, err := s.resolver.Query().QueryEdits(s.ctx, models.EditQueryInput{ IsBot: &botTrue, Page: 1, PerPage: 25, Direction: models.SortDirectionEnumDesc, Sort: models.EditSortEnumCreatedAt, }) assert.NoError(s.t, err) editsResultBot, err := s.resolver.QueryEditsResultType().Edits(s.ctx, resultBot) assert.NoError(s.t, err) countBot, err := s.resolver.QueryEditsResultType().Count(s.ctx, resultBot) assert.NoError(s.t, err) assert.Equal(s.t, 1, countBot, "Should have exactly 1 bot edit") assert.Equal(s.t, 1, len(editsResultBot), "Should return exactly 1 bot edit") assert.Equal(s.t, editWithBotTrue.ID, editsResultBot[0].ID, "Returned bot edit should match the one we created") assert.True(s.t, editsResultBot[0].Bot, "Returned edit should have bot=true") } func TestBotFlag(t *testing.T) { pt := createEditTestRunner(t) pt.testBotFlag() } ================================================ FILE: internal/api/field_test.go ================================================ //go:build integration package api_test import ( "database/sql" "github.com/gofrs/uuid" ) type fieldComparator struct { r *testRunner } func (c *fieldComparator) strPtrStrPtr(expected *string, actual *string, field string) { c.r.t.Helper() if expected == actual { return } matched := true if expected == nil || actual == nil { matched = false } else { matched = *expected == *actual } if !matched { c.r.fieldMismatch(expected, actual, field) } } func (c *fieldComparator) strPtrNullStr(expected *string, actual sql.NullString, field string) { c.r.t.Helper() if expected == nil && !actual.Valid { return } matched := true if expected == nil || !actual.Valid { matched = false } else { matched = *expected == actual.String } if !matched { c.r.fieldMismatch(expected, actual.String, field) } } func (c *fieldComparator) strPtrNullUUID(expected *string, actual uuid.NullUUID, field string) { c.r.t.Helper() if expected == nil && !actual.Valid { return } matched := true if expected == nil || !actual.Valid { matched = false } else { matched = *expected == actual.UUID.String() } if !matched { c.r.fieldMismatch(expected, actual.UUID.String(), field) } } func (c *fieldComparator) intPtrIntPtr(expected *int, actual *int, field string) { c.r.t.Helper() if expected == actual { return } matched := true if expected == nil || actual == nil { matched = false } else { matched = *expected == *actual } if !matched { c.r.fieldMismatch(expected, actual, field) } } func (c *fieldComparator) uuidPtrUUIDPtr(expected *uuid.UUID, actual *uuid.UUID, field string) { c.r.t.Helper() if expected == actual { return } matched := true if expected == nil || actual == nil { matched = false } else { matched = *expected == *actual } if !matched { c.r.fieldMismatch(expected, actual, field) } } func (c *fieldComparator) uuidPtrNullUUID(expected *uuid.UUID, actual uuid.NullUUID, field string) { c.r.t.Helper() if expected == nil && !actual.Valid { return } matched := true if expected == nil || !actual.Valid { matched = false } else { matched = *expected == actual.UUID } if !matched { c.r.fieldMismatch(expected, actual.UUID, field) } } ================================================ FILE: internal/api/fingerprint_filter.go ================================================ package api import "github.com/stashapp/stash-box/internal/models" // filterMD5FingerprintInputs removes MD5 fingerprints from a slice. func filterMD5FingerprintInputs(fps []models.FingerprintInput) []models.FingerprintInput { result := fps[:0] for _, fp := range fps { if fp.Algorithm != models.FingerprintAlgorithmMd5 { result = append(result, fp) } } return result } // filterMD5FingerprintQueryInputs removes MD5 fingerprints from nested slices. func filterMD5FingerprintQueryInputs(fps [][]models.FingerprintQueryInput) [][]models.FingerprintQueryInput { for i, group := range fps { filtered := group[:0] for _, fp := range group { if fp.Algorithm != models.FingerprintAlgorithmMd5 { filtered = append(filtered, fp) } } fps[i] = filtered } return fps } // filterMD5FingerprintEditInputs removes MD5 fingerprints from a slice. func filterMD5FingerprintEditInputs(fps []models.FingerprintEditInput) []models.FingerprintEditInput { result := fps[:0] for _, fp := range fps { if fp.Algorithm != models.FingerprintAlgorithmMd5 { result = append(result, fp) } } return result } ================================================ FILE: internal/api/graphql_client_test.go ================================================ //go:build integration package api_test import ( "reflect" "strings" "github.com/99designs/gqlgen/client" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" ) type idObject struct { ID string `json:"id"` } type performerAppearance struct { Performer *idObject `json:"performer"` // Performing as alias As *string `json:"as"` } type fingerprint struct { Hash string `json:"hash"` Algorithm models.FingerprintAlgorithm `json:"algorithm"` Duration int `json:"duration"` Submissions int `json:"submissions"` Created string `json:"created"` Updated string `json:"updated"` } // FingerprintHash returns the Hash as a models.FingerprintHash func (f fingerprint) FingerprintHash() models.FingerprintHash { h, _ := models.UnmarshalFingerprintHash(f.Hash) return h } type siteURL struct { Site *idObject `json:"site"` URL string `json:"url"` } type sceneOutput struct { ID string `json:"id"` Title *string `json:"title"` Details *string `json:"details"` Date *string `json:"release_date"` ProductionDate *string `json:"production_date"` Urls []siteURL `json:"urls"` Studio *idObject `json:"studio"` Tags []idObject `json:"tags"` Images []idObject `json:"images"` Performers []performerAppearance `json:"performers"` Fingerprints []fingerprint `json:"fingerprints"` Duration *int `json:"duration"` Director *string `json:"director"` Code *string `json:"code"` Deleted bool `json:"deleted"` } func (s sceneOutput) UUID() uuid.UUID { return uuid.FromStringOrNil(s.ID) } type queryScenesResultType struct { Count int `json:"count"` Scenes []sceneOutput `json:"scenes"` } type measurements struct { CupSize *string `json:"cup_size"` BandSize *int `json:"band_size"` Waist *int `json:"waist"` Hip *int `json:"hip"` } type performerOutput struct { ID string `json:"id"` Name string `json:"name"` Disambiguation *string `json:"disambiguation"` Gender *string `json:"gender"` Birthdate *string `json:"birth_date"` Deathdate *string `json:"death_date"` Ethnicity *string `json:"ethnicity"` Country *string `json:"country"` EyeColor *string `json:"eye_color"` HairColor *string `json:"hair_color"` Height *int `json:"height"` Measurements *measurements `json:"measurements"` BreastType *string `json:"breast_type"` CareerStartYear *int `json:"career_start_year"` CareerEndYear *int `json:"career_end_year"` } func (p performerOutput) UUID() uuid.UUID { return uuid.FromStringOrNil(p.ID) } type studioOutput struct { ID string `json:"id"` Name string `json:"name"` Urls []siteURL `json:"urls"` Parent *idObject `json:"parent"` ChildStudios []idObject `json:"child_studios"` Images []idObject `json:"images"` Deleted bool `json:"deleted"` } func (s studioOutput) UUID() uuid.UUID { return uuid.FromStringOrNil(s.ID) } type tagOutput struct { ID string `json:"id"` Name string `json:"name"` Description *string `json:"description"` Aliases []string `json:"aliases"` Deleted bool `json:"deleted"` Edits []idObject `json:"edits"` Category *idObject `json:"category"` } func (t tagOutput) UUID() uuid.UUID { return uuid.FromStringOrNil(t.ID) } type siteOutput struct { ID string `json:"id"` Name string `json:"name"` Description *string `json:"description"` URL *string `json:"url"` Regex *string `json:"regex"` ValidTypes []string `json:"valid_types"` } func (s siteOutput) UUID() uuid.UUID { return uuid.FromStringOrNil(s.ID) } type querySitesResultType struct { Sites []siteOutput `json:"sites"` } type queryPerformersResultType struct { Count int `json:"count"` Performers []performerOutput `json:"performers"` } type queryStudiosResultType struct { Count int `json:"count"` Studios []studioOutput `json:"studios"` } type queryTagsResultType struct { Count int `json:"count"` Tags []tagOutput `json:"tags"` } type tagCategoryOutput struct { ID string `json:"id"` Name string `json:"name"` Description *string `json:"description"` } func (tc tagCategoryOutput) UUID() uuid.UUID { return uuid.FromStringOrNil(tc.ID) } type queryTagCategoriesResultType struct { Count int `json:"count"` TagCategories []tagCategoryOutput `json:"tag_categories"` } type userOutput struct { ID string `json:"id"` Name string `json:"name"` } func (u userOutput) UUID() uuid.UUID { return uuid.FromStringOrNil(u.ID) } type draftSubmissionStatusOutput struct { ID *string `json:"id"` } func (d draftSubmissionStatusOutput) UUID() *uuid.UUID { if d.ID == nil { return nil } id := uuid.FromStringOrNil(*d.ID) return &id } type draftEntityOutput struct { Name string `json:"name"` ID *string `json:"id"` } type draftFingerprintOutput struct { Hash string `json:"hash"` Algorithm string `json:"algorithm"` Duration int `json:"duration"` } type sceneDraftOutput struct { ID *string `json:"id"` Title *string `json:"title"` Code *string `json:"code"` Details *string `json:"details"` Director *string `json:"director"` URLs []string `json:"urls"` Date *string `json:"date"` Studio *draftEntityOutput `json:"studio"` Performers []draftEntityOutput `json:"performers"` Tags []draftEntityOutput `json:"tags"` Fingerprints []draftFingerprintOutput `json:"fingerprints"` } type performerDraftOutput struct { ID *string `json:"id"` Name string `json:"name"` Disambiguation *string `json:"disambiguation"` Aliases *string `json:"aliases"` Gender *string `json:"gender"` Birthdate *string `json:"birthdate"` Deathdate *string `json:"deathdate"` Urls []string `json:"urls"` Ethnicity *string `json:"ethnicity"` Country *string `json:"country"` EyeColor *string `json:"eye_color"` HairColor *string `json:"hair_color"` Height *string `json:"height"` Measurements *string `json:"measurements"` BreastType *string `json:"breast_type"` Tattoos *string `json:"tattoos"` Piercings *string `json:"piercings"` CareerStartYear *int `json:"career_start_year"` CareerEndYear *int `json:"career_end_year"` } type draftOutput struct { ID string `json:"id"` Created string `json:"created"` Expires string `json:"expires"` Data interface{} `json:"data"` } func (d draftOutput) UUID() uuid.UUID { return uuid.FromStringOrNil(d.ID) } type notificationOutput struct { Created string `json:"created"` Read bool `json:"read"` } type queryNotificationsResultType struct { Count int `json:"count"` Notifications []notificationOutput `json:"notifications"` } func makeFragment(t reflect.Type) string { ret := strings.Builder{} for i := 0; i < t.NumField(); i++ { f := t.Field(i) v := f.Tag.Get("json") if i > 0 { v = "\n" + v } ft := f.Type if ft.Kind() == reflect.Slice { ft = ft.Elem() } if ft.Kind() == reflect.Ptr { ft = ft.Elem() } if ft.Kind() == reflect.Struct { v = v + " {\n" + makeFragment(ft) + "\n}" } ret.WriteString(v) } return ret.String() } type graphqlClient struct { *client.Client } func (c *graphqlClient) createScene(input models.SceneCreateInput) (*sceneOutput, error) { q := ` mutation SceneCreate($input: SceneCreateInput!) { sceneCreate(input: $input) { ` + makeFragment(reflect.TypeOf(sceneOutput{})) + ` } }` var resp struct { SceneCreate *sceneOutput } if err := c.Post(q, &resp, client.Var("input", input)); err != nil { return nil, err } return resp.SceneCreate, nil } func (c *graphqlClient) findScene(id uuid.UUID) (*sceneOutput, error) { q := ` query FindScene($id: ID!) { findScene(id: $id) { ` + makeFragment(reflect.TypeOf(sceneOutput{})) + ` } }` var resp struct { FindScene *sceneOutput } if err := c.Post(q, &resp, client.Var("id", id)); err != nil { return nil, err } return resp.FindScene, nil } func (c *graphqlClient) findScenesBySceneFingerprints(sceneFingerprints [][]models.FingerprintQueryInput) ([][]*sceneOutput, error) { q := ` query FindScenesBySceneFingerprints($input: [[FingerprintQueryInput!]!]!) { findScenesBySceneFingerprints(fingerprints: $input) { ` + makeFragment(reflect.TypeOf(sceneOutput{})) + ` } }` var resp struct { FindScenesBySceneFingerprints [][]*sceneOutput } if err := c.Post(q, &resp, client.Var("input", sceneFingerprints)); err != nil { return nil, err } return resp.FindScenesBySceneFingerprints, nil } func (c *graphqlClient) queryScenes(input models.SceneQueryInput) (*queryScenesResultType, error) { q := ` query QueryScenes($input: SceneQueryInput!) { queryScenes(input: $input) { ` + makeFragment(reflect.TypeOf(queryScenesResultType{})) + ` } }` var resp struct { QueryScenes *queryScenesResultType } if err := c.Post(q, &resp, client.Var("input", input)); err != nil { return nil, err } return resp.QueryScenes, nil } func (c *graphqlClient) updateScene(updateInput models.SceneUpdateInput) (*sceneOutput, error) { q := ` mutation SceneUpdate($input: SceneUpdateInput!) { sceneUpdate(input: $input) { ` + makeFragment(reflect.TypeOf(sceneOutput{})) + ` } }` var resp struct { SceneUpdate *sceneOutput } if err := c.Post(q, &resp, client.Var("input", updateInput)); err != nil { return nil, err } return resp.SceneUpdate, nil } func (c *graphqlClient) destroyScene(input models.SceneDestroyInput) (bool, error) { q := ` mutation SceneDestroy($input: SceneDestroyInput!) { sceneDestroy(input: $input) }` var resp struct { SceneDestroy bool } if err := c.Post(q, &resp, client.Var("input", input)); err != nil { return false, err } return resp.SceneDestroy, nil } func (c *graphqlClient) submitFingerprint(input models.FingerprintSubmission) (bool, error) { q := ` mutation SubmitFingerprint($input: FingerprintSubmission!) { submitFingerprint(input: $input) }` var resp struct { SubmitFingerprint bool } if err := c.Post(q, &resp, client.Var("input", input)); err != nil { return false, err } return resp.SubmitFingerprint, nil } type fingerprintSubmissionResultOutput struct { Hash string `json:"hash"` SceneID string `json:"scene_id"` Error *string `json:"error"` } func (c *graphqlClient) submitFingerprints(input []models.FingerprintBatchSubmission) ([]models.FingerprintSubmissionResult, error) { q := ` mutation SubmitFingerprints($input: [FingerprintBatchSubmission!]!) { submitFingerprints(input: $input) { hash scene_id error } }` var resp struct { SubmitFingerprints []fingerprintSubmissionResultOutput } if err := c.Post(q, &resp, client.Var("input", input)); err != nil { return nil, err } // Convert output to models results := make([]models.FingerprintSubmissionResult, len(resp.SubmitFingerprints)) for i, r := range resp.SubmitFingerprints { hash, _ := models.UnmarshalFingerprintHash(r.Hash) results[i] = models.FingerprintSubmissionResult{ Hash: hash, SceneID: uuid.FromStringOrNil(r.SceneID), Error: r.Error, } } return results, nil } func (c *graphqlClient) sceneMoveFingerprintSubmissions(input models.MoveFingerprintSubmissionsInput) (bool, error) { q := ` mutation SceneMoveFingerprintSubmissions($input: MoveFingerprintSubmissionsInput!) { sceneMoveFingerprintSubmissions(input: $input) }` var resp struct { SceneMoveFingerprintSubmissions bool } if err := c.Post(q, &resp, client.Var("input", input)); err != nil { return false, err } return resp.SceneMoveFingerprintSubmissions, nil } func (c *graphqlClient) sceneDeleteFingerprintSubmissions(input models.DeleteFingerprintSubmissionsInput) (bool, error) { q := ` mutation SceneDeleteFingerprintSubmissions($input: DeleteFingerprintSubmissionsInput!) { sceneDeleteFingerprintSubmissions(input: $input) }` var resp struct { SceneDeleteFingerprintSubmissions bool } if err := c.Post(q, &resp, client.Var("input", input)); err != nil { return false, err } return resp.SceneDeleteFingerprintSubmissions, nil } func (c *graphqlClient) createPerformer(input models.PerformerCreateInput) (*performerOutput, error) { q := ` mutation PerformerCreate($input: PerformerCreateInput!) { performerCreate(input: $input) { ` + makeFragment(reflect.TypeOf(performerOutput{})) + ` } }` var resp struct { PerformerCreate *performerOutput } if err := c.Post(q, &resp, client.Var("input", input)); err != nil { return nil, err } return resp.PerformerCreate, nil } func (c *graphqlClient) findPerformer(id uuid.UUID) (*performerOutput, error) { q := ` query FindPerformer($id: ID!) { findPerformer(id: $id) { ` + makeFragment(reflect.TypeOf(performerOutput{})) + ` } }` var resp struct { FindPerformer *performerOutput } if err := c.Post(q, &resp, client.Var("id", id)); err != nil { return nil, err } return resp.FindPerformer, nil } func (c *graphqlClient) createStudio(input models.StudioCreateInput) (*studioOutput, error) { q := ` mutation StudioCreate($input: StudioCreateInput!) { studioCreate(input: $input) { ` + makeFragment(reflect.TypeOf(studioOutput{})) + ` } }` var resp struct { StudioCreate *studioOutput } if err := c.Post(q, &resp, client.Var("input", input)); err != nil { return nil, err } return resp.StudioCreate, nil } func (c *graphqlClient) findStudio(id uuid.UUID) (*studioOutput, error) { q := ` query FindStudio($id: ID!) { findStudio(id: $id) { ` + makeFragment(reflect.TypeOf(studioOutput{})) + ` } }` var resp struct { FindStudio *studioOutput } if err := c.Post(q, &resp, client.Var("id", id)); err != nil { return nil, err } return resp.FindStudio, nil } func (c *graphqlClient) createTag(input models.TagCreateInput) (*tagOutput, error) { q := ` mutation TagCreate($input: TagCreateInput!) { tagCreate(input: $input) { ` + makeFragment(reflect.TypeOf(tagOutput{})) + ` } }` var resp struct { TagCreate *tagOutput } if err := c.Post(q, &resp, client.Var("input", input)); err != nil { return nil, err } return resp.TagCreate, nil } func (c *graphqlClient) findSite(id uuid.UUID) (*siteOutput, error) { q := ` query FindSite($id: ID!) { findSite(id: $id) { ` + makeFragment(reflect.TypeOf(siteOutput{})) + ` } }` var resp struct { FindSite *siteOutput } if err := c.Post(q, &resp, client.Var("id", id)); err != nil { return nil, err } return resp.FindSite, nil } func (c *graphqlClient) querySites() (*querySitesResultType, error) { q := ` query QuerySites { querySites { ` + makeFragment(reflect.TypeOf(querySitesResultType{})) + ` } }` var resp struct { QuerySites *querySitesResultType } if err := c.Post(q, &resp); err != nil { return nil, err } return resp.QuerySites, nil } func (c *graphqlClient) updateSite(input models.SiteUpdateInput) (*siteOutput, error) { q := ` mutation SiteUpdate($input: SiteUpdateInput!) { siteUpdate(input: $input) { ` + makeFragment(reflect.TypeOf(siteOutput{})) + ` } }` var resp struct { SiteUpdate *siteOutput } if err := c.Post(q, &resp, client.Var("input", input)); err != nil { return nil, err } return resp.SiteUpdate, nil } func (c *graphqlClient) destroySite(input models.SiteDestroyInput) (bool, error) { q := ` mutation SiteDestroy($input: SiteDestroyInput!) { siteDestroy(input: $input) }` var resp struct { SiteDestroy bool } if err := c.Post(q, &resp, client.Var("input", input)); err != nil { return false, err } return resp.SiteDestroy, nil } func (c *graphqlClient) queryPerformers(input models.PerformerQueryInput) (*queryPerformersResultType, error) { q := ` query QueryPerformers($input: PerformerQueryInput!) { queryPerformers(input: $input) { ` + makeFragment(reflect.TypeOf(queryPerformersResultType{})) + ` } }` var resp struct { QueryPerformers *queryPerformersResultType } if err := c.Post(q, &resp, client.Var("input", input)); err != nil { return nil, err } return resp.QueryPerformers, nil } func (c *graphqlClient) queryStudios(input models.StudioQueryInput) (*queryStudiosResultType, error) { q := ` query QueryStudios($input: StudioQueryInput!) { queryStudios(input: $input) { ` + makeFragment(reflect.TypeOf(queryStudiosResultType{})) + ` } }` var resp struct { QueryStudios *queryStudiosResultType } if err := c.Post(q, &resp, client.Var("input", input)); err != nil { return nil, err } return resp.QueryStudios, nil } func (c *graphqlClient) queryTags(input models.TagQueryInput) (*queryTagsResultType, error) { q := ` query QueryTags($input: TagQueryInput!) { queryTags(input: $input) { ` + makeFragment(reflect.TypeOf(queryTagsResultType{})) + ` } }` var resp struct { QueryTags *queryTagsResultType } if err := c.Post(q, &resp, client.Var("input", input)); err != nil { return nil, err } return resp.QueryTags, nil } func (c *graphqlClient) queryTagCategories() (*queryTagCategoriesResultType, error) { q := ` query QueryTagCategories { queryTagCategories { ` + makeFragment(reflect.TypeOf(queryTagCategoriesResultType{})) + ` } }` var resp struct { QueryTagCategories *queryTagCategoriesResultType } if err := c.Post(q, &resp); err != nil { return nil, err } return resp.QueryTagCategories, nil } func (c *graphqlClient) findTagOrAlias(name string) (*tagOutput, error) { q := ` query FindTagOrAlias($name: String!) { findTagOrAlias(name: $name) { ` + makeFragment(reflect.TypeOf(tagOutput{})) + ` } }` var resp struct { FindTagOrAlias *tagOutput } if err := c.Post(q, &resp, client.Var("name", name)); err != nil { return nil, err } return resp.FindTagOrAlias, nil } func (c *graphqlClient) me() (*userOutput, error) { q := ` query Me { me { ` + makeFragment(reflect.TypeOf(userOutput{})) + ` } }` var resp struct { Me *userOutput } if err := c.Post(q, &resp); err != nil { return nil, err } return resp.Me, nil } func (c *graphqlClient) favoritePerformer(id uuid.UUID, favorite bool) (bool, error) { q := ` mutation FavoritePerformer($id: ID!, $favorite: Boolean!) { favoritePerformer(id: $id, favorite: $favorite) }` var resp struct { FavoritePerformer bool } if err := c.Post(q, &resp, client.Var("id", id), client.Var("favorite", favorite)); err != nil { return false, err } return resp.FavoritePerformer, nil } func (c *graphqlClient) favoriteStudio(id uuid.UUID, favorite bool) (bool, error) { q := ` mutation FavoriteStudio($id: ID!, $favorite: Boolean!) { favoriteStudio(id: $id, favorite: $favorite) }` var resp struct { FavoriteStudio bool } if err := c.Post(q, &resp, client.Var("id", id), client.Var("favorite", favorite)); err != nil { return false, err } return resp.FavoriteStudio, nil } func (c *graphqlClient) submitSceneDraft(input models.SceneDraftInput) (*draftSubmissionStatusOutput, error) { q := ` mutation SubmitSceneDraft($input: SceneDraftInput!) { submitSceneDraft(input: $input) { id } }` var resp struct { SubmitSceneDraft draftSubmissionStatusOutput } if err := c.Post(q, &resp, client.Var("input", input)); err != nil { return nil, err } return &resp.SubmitSceneDraft, nil } func (c *graphqlClient) submitPerformerDraft(input models.PerformerDraftInput) (*draftSubmissionStatusOutput, error) { q := ` mutation SubmitPerformerDraft($input: PerformerDraftInput!) { submitPerformerDraft(input: $input) { id } }` var resp struct { SubmitPerformerDraft draftSubmissionStatusOutput } if err := c.Post(q, &resp, client.Var("input", input)); err != nil { return nil, err } return &resp.SubmitPerformerDraft, nil } func (c *graphqlClient) findDraft(id uuid.UUID) (*draftOutput, error) { q := ` query FindDraft($id: ID!) { findDraft(id: $id) { id created expires } }` var resp struct { FindDraft *draftOutput } if err := c.Post(q, &resp, client.Var("id", id)); err != nil { return nil, err } return resp.FindDraft, nil } func (c *graphqlClient) findDraftWithTags(id uuid.UUID) (*draftOutput, error) { q := ` query FindDraft($id: ID!) { findDraft(id: $id) { id created expires data { ... on SceneDraft { tags { __typename ... on Tag { id name } ... on DraftEntity { name } } } } } }` var resp struct { FindDraft *draftOutput } if err := c.Post(q, &resp, client.Var("id", id)); err != nil { return nil, err } return resp.FindDraft, nil } func (c *graphqlClient) findDrafts() ([]draftOutput, error) { q := ` query FindDrafts { findDrafts { id created expires } }` var resp struct { FindDrafts []draftOutput } if err := c.Post(q, &resp); err != nil { return nil, err } return resp.FindDrafts, nil } func (c *graphqlClient) destroyDraft(id uuid.UUID) (bool, error) { q := ` mutation DestroyDraft($id: ID!) { destroyDraft(id: $id) }` var resp struct { DestroyDraft bool } if err := c.Post(q, &resp, client.Var("id", id)); err != nil { return false, err } return resp.DestroyDraft, nil } func (c *graphqlClient) queryNotifications(input models.QueryNotificationsInput) (*queryNotificationsResultType, error) { q := ` query QueryNotifications($input: QueryNotificationsInput!) { queryNotifications(input: $input) { count notifications { created read } } }` var resp struct { QueryNotifications queryNotificationsResultType } if err := c.Post(q, &resp, client.Var("input", input)); err != nil { return nil, err } return &resp.QueryNotifications, nil } func (c *graphqlClient) getUnreadNotificationCount() (int, error) { q := ` query GetUnreadNotificationCount { getUnreadNotificationCount }` var resp struct { GetUnreadNotificationCount int } if err := c.Post(q, &resp); err != nil { return 0, err } return resp.GetUnreadNotificationCount, nil } func (c *graphqlClient) updateNotificationSubscriptions(subscriptions []models.NotificationEnum) (bool, error) { q := ` mutation UpdateNotificationSubscriptions($subscriptions: [NotificationEnum!]!) { updateNotificationSubscriptions(subscriptions: $subscriptions) }` var resp struct { UpdateNotificationSubscriptions bool } if err := c.Post(q, &resp, client.Var("subscriptions", subscriptions)); err != nil { return false, err } return resp.UpdateNotificationSubscriptions, nil } func (c *graphqlClient) markNotificationsRead(notification *models.MarkNotificationReadInput) (bool, error) { q := ` mutation MarkNotificationsRead($notification: MarkNotificationReadInput) { markNotificationsRead(notification: $notification) }` var resp struct { MarkNotificationsRead bool } if err := c.Post(q, &resp, client.Var("notification", notification)); err != nil { return false, err } return resp.MarkNotificationsRead, nil } func (c *graphqlClient) getNotificationSubscriptions() ([]models.NotificationEnum, error) { q := ` query Me { me { notification_subscriptions } }` var resp struct { Me struct { NotificationSubscriptions []models.NotificationEnum `json:"notification_subscriptions"` } } if err := c.Post(q, &resp); err != nil { return nil, err } return resp.Me.NotificationSubscriptions, nil } func (c *graphqlClient) deleteEdit(input models.DeleteEditInput) (bool, error) { q := ` mutation DeleteEdit($input: DeleteEditInput!) { deleteEdit(input: $input) }` var resp struct { DeleteEdit bool } if err := c.Post(q, &resp, client.Var("input", input)); err != nil { return false, err } return resp.DeleteEdit, nil } func (c *graphqlClient) amendEdit(input models.AmendEditInput) (bool, error) { q := ` mutation AmendEdit($input: AmendEditInput!) { amendEdit(input: $input) { id } }` var resp struct { AmendEdit struct { ID uuid.UUID } } if err := c.Post(q, &resp, client.Var("input", input)); err != nil { return false, err } return resp.AmendEdit.ID != uuid.Nil, nil } ================================================ FILE: internal/api/integration_test.go ================================================ //go:build integration package api_test import ( "context" "net/http" "strconv" "testing" "github.com/stashapp/stash-box/internal/api" "github.com/stashapp/stash-box/internal/auth" dbtest "github.com/stashapp/stash-box/internal/database/testutil" "github.com/stashapp/stash-box/internal/dataloader" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/internal/service" "github.com/99designs/gqlgen/client" "github.com/99designs/gqlgen/graphql" "github.com/99designs/gqlgen/graphql/handler" "github.com/gofrs/uuid" "github.com/stretchr/testify/assert" ) // we need to create some users to test the api with, otherwise all calls // will be unauthorised type userPopulator struct { none *models.User read *models.User admin *models.User modify *models.User moderate *models.User edit *models.User noneRoles []models.RoleEnum readRoles []models.RoleEnum adminRoles []models.RoleEnum modifyRoles []models.RoleEnum moderateRoles []models.RoleEnum editRoles []models.RoleEnum } var userDB *userPopulator func (p *userPopulator) PopulateDB(factory *service.Factory) error { ctx := context.TODO() userService := factory.User() // create admin user createInput := models.UserCreateInput{ Name: "admin", Password: "TestPassword#2024", Roles: []models.RoleEnum{ models.RoleEnumAdmin, }, Email: "admin@example.com", } var err error p.admin, err = userService.Create(ctx, createInput) p.adminRoles = createInput.Roles if err != nil { return err } // create modify user createInput = models.UserCreateInput{ Name: "modify", Password: "TestPassword#2024", Roles: []models.RoleEnum{ models.RoleEnumModify, }, Email: "modify@example.com", } p.modify, err = userService.Create(ctx, createInput) p.modifyRoles = createInput.Roles if err != nil { return err } // create moderate user createInput = models.UserCreateInput{ Name: "moderate", Password: "TestPassword#2024", Roles: []models.RoleEnum{ models.RoleEnumModerate, }, Email: "moderate@example.com", } p.moderate, err = userService.Create(ctx, createInput) p.moderateRoles = createInput.Roles if err != nil { return err } // create edit user createInput = models.UserCreateInput{ Name: "edit", Password: "TestPassword#2024", Roles: []models.RoleEnum{ models.RoleEnumEdit, }, Email: "edit@example.com", } p.edit, err = userService.Create(ctx, createInput) p.editRoles = createInput.Roles if err != nil { return err } // create read user createInput = models.UserCreateInput{ Name: "read", Password: "TestPassword#2024", Roles: []models.RoleEnum{ models.RoleEnumRead, }, Email: "read@example.com", } p.read, err = userService.Create(ctx, createInput) p.readRoles = createInput.Roles if err != nil { return err } // create none user createInput = models.UserCreateInput{ Name: "none", Password: "TestPassword#2024", Roles: []models.RoleEnum{ models.RoleEnumRead, }, Email: "none@example.com", } p.none, err = userService.Create(ctx, createInput) if err != nil { return err } // create other users as needed return nil } func TestMain(m *testing.M) { userDB = &userPopulator{} dbtest.TestWithDatabase(m, userDB) } type testRunner struct { t *testing.T client *graphqlClient resolver api.Resolver ctx context.Context err error } var sceneSuffix int var performerSuffix int var studioSuffix int var tagSuffix int var sceneChecksumSuffix int var userSuffix int var categorySuffix int var siteSuffix int func createTestRunner(t *testing.T, u *models.User, roles []models.RoleEnum) *testRunner { resolver := api.NewResolver(*dbtest.Factory()) gqlHandler := handler.NewDefaultServer(models.NewExecutableSchema(models.Config{ Resolvers: resolver, Directives: models.DirectiveRoot{ IsUserOwner: api.IsUserOwnerDirective, HasRole: api.HasRoleDirective, }, })) var handlerFunc http.HandlerFunc = func(w http.ResponseWriter, r *http.Request) { // re-create context for each request ctx := context.TODO() ctx = context.WithValue(ctx, auth.ContextUser, u) ctx = context.WithValue(ctx, auth.ContextRoles, roles) ctx = context.WithValue(ctx, dataloader.GetLoadersKey(), dataloader.GetLoaders(ctx, *dbtest.Factory())) ctx = graphql.WithOperationContext(ctx, &graphql.OperationContext{}) r = r.WithContext(ctx) gqlHandler.ServeHTTP(w, r) } c := client.New(handlerFunc) // replicate what the server.go code does ctx := context.TODO() ctx = context.WithValue(ctx, auth.ContextUser, u) ctx = context.WithValue(ctx, auth.ContextRoles, roles) ctx = context.WithValue(ctx, dataloader.GetLoadersKey(), dataloader.GetLoaders(ctx, *dbtest.Factory())) ctx = graphql.WithOperationContext(ctx, &graphql.OperationContext{}) return &testRunner{ t: t, client: &graphqlClient{ c, }, resolver: *resolver, ctx: ctx, } } func asAdmin(t *testing.T) *testRunner { return createTestRunner(t, userDB.admin, userDB.adminRoles) } func asModify(t *testing.T) *testRunner { return createTestRunner(t, userDB.modify, userDB.modifyRoles) } func asModerate(t *testing.T) *testRunner { return createTestRunner(t, userDB.moderate, userDB.moderateRoles) } func asRead(t *testing.T) *testRunner { return createTestRunner(t, userDB.read, userDB.readRoles) } func asNone(t *testing.T) *testRunner { return createTestRunner(t, userDB.none, userDB.noneRoles) } func asEdit(t *testing.T) *testRunner { return createTestRunner(t, userDB.edit, userDB.editRoles) } func (t *testRunner) doTest(test func()) { if t.t.Failed() { return } test() } func (t *testRunner) fieldMismatch(expected interface{}, actual interface{}, field string) { t.t.Helper() t.t.Errorf("%s mismatch: %+v != %+v", field, actual, expected) } func (t *testRunner) updateContext(fields []string) context.Context { variables := make(map[string]interface{}) for _, v := range fields { variables[v] = true } rctx := &graphql.OperationContext{ Variables: variables, } return graphql.WithOperationContext(t.ctx, rctx) } func (s *testRunner) generatePerformerName() string { performerSuffix += 1 return "performer-" + strconv.Itoa(performerSuffix) } func (s *testRunner) createTestPerformer(input *models.PerformerCreateInput) (*performerOutput, error) { s.t.Helper() if input == nil { input = &models.PerformerCreateInput{ Name: s.generatePerformerName(), } } createdPerformer, err := s.client.createPerformer(*input) if err != nil { s.t.Errorf("Error creating performer: %s", err.Error()) return nil, err } return createdPerformer, nil } func (s *testRunner) createFullPerformerCreateInput() *models.PerformerCreateInput { name := s.generatePerformerName() disambiguation := "Dis Ambiguation" gender := models.GenderEnumFemale ethnicity := models.EthnicityEnumCaucasian eyecolor := models.EyeColorEnumBlue haircolor := models.HairColorEnumAuburn country := "Some Country" height := 160 hip := 23 waist := 24 band := 25 cup := "DD" breasttype := models.BreastTypeEnumNatural careerstart := 2019 careerend := 2020 tattoodesc := "Tatto Desc" birthdate := "2000-02-03" deathdate := "2024-01-02" site, err := s.createTestSite(nil) if err != nil { return nil } return &models.PerformerCreateInput{ Name: name, Disambiguation: &disambiguation, Aliases: []string{"Alias1"}, Gender: &gender, Urls: []models.URL{ { URL: "http://example.org", SiteID: site.ID, }, }, Birthdate: &birthdate, Deathdate: &deathdate, Ethnicity: ðnicity, Country: &country, EyeColor: &eyecolor, HairColor: &haircolor, Height: &height, HipSize: &hip, WaistSize: &waist, BandSize: &band, CupSize: &cup, BreastType: &breasttype, CareerStartYear: &careerstart, CareerEndYear: &careerend, Tattoos: []models.BodyModificationInput{ { Location: "Wrist", Description: &tattoodesc, }, }, Piercings: []models.BodyModificationInput{ { Location: "Ears", }, }, } } func (s *testRunner) generateStudioName() string { studioSuffix += 1 return "studio-" + strconv.Itoa(studioSuffix) } func (s *testRunner) createTestStudio(input *models.StudioCreateInput) (*studioOutput, error) { s.t.Helper() if input == nil { input = &models.StudioCreateInput{ Name: s.generateStudioName(), } } createdStudio, err := s.client.createStudio(*input) if err != nil { s.t.Errorf("Error creating studio: %s", err.Error()) return nil, err } return createdStudio, nil } func (s *testRunner) generateTagName() string { tagSuffix += 1 return "testtag" + strconv.Itoa(tagSuffix) } func (s *testRunner) createTestTag(input *models.TagCreateInput) (*tagOutput, error) { s.t.Helper() if input == nil { input = &models.TagCreateInput{ Name: s.generateTagName(), } } createdTag, err := s.client.createTag(*input) if err != nil { s.t.Errorf("Error creating tag: %s", err.Error()) return nil, err } return createdTag, nil } func (s *testRunner) generateSceneName() string { sceneSuffix += 1 return "scene-" + strconv.Itoa(sceneSuffix) } func (s *testRunner) createTestScene(input *models.SceneCreateInput) (*sceneOutput, error) { s.t.Helper() if input == nil { title := s.generateSceneName() input = &models.SceneCreateInput{ Title: &title, Fingerprints: []models.FingerprintEditInput{ s.generateSceneFingerprint(nil), }, Date: "2020-03-02", } } if input.Fingerprints == nil { input.Fingerprints = []models.FingerprintEditInput{} } createdScene, err := s.client.createScene(*input) if err != nil { s.t.Errorf("Error creating scene: %s", err.Error()) return nil, err } return createdScene, nil } func (s *testRunner) generateSceneFingerprint(userIDs []uuid.UUID) models.FingerprintEditInput { return s.generateSceneFingerprintWithAlgorithm(models.FingerprintAlgorithmOshash, userIDs) } func (s *testRunner) generateSceneFingerprintWithAlgorithm(algorithm models.FingerprintAlgorithm, userIDs []uuid.UUID) models.FingerprintEditInput { if userIDs == nil { userIDs = []uuid.UUID{} } sceneChecksumSuffix += 1 return models.FingerprintEditInput{ Algorithm: algorithm, Hash: models.FingerprintHash(sceneChecksumSuffix), Duration: 1234, UserIds: userIDs, } } func (s *testRunner) generateUserName() string { userSuffix += 1 return "user-" + strconv.Itoa(userSuffix) } func (s *testRunner) createTestUser(input *models.UserCreateInput, roles []models.RoleEnum) (*models.User, error) { s.t.Helper() userRoles := roles if roles == nil { userRoles = []models.RoleEnum{ models.RoleEnumAdmin, } } if input == nil { name := s.generateUserName() input = &models.UserCreateInput{ Name: name, Email: name + "@example.com", Password: "password" + name, Roles: userRoles, } } createdUser, err := s.resolver.Mutation().UserCreate(s.ctx, *input) if err != nil { s.t.Errorf("Error creating user: %s", err.Error()) return nil, err } return createdUser, nil } func (s *testRunner) generateCategoryName() string { categorySuffix += 1 return "category-" + strconv.Itoa(categorySuffix) } func (s *testRunner) createTestTagCategory(input *models.TagCategoryCreateInput) (*models.TagCategory, error) { s.t.Helper() if input == nil { name := s.generateCategoryName() desc := "Description for " + name input = &models.TagCategoryCreateInput{ Name: name, Description: &desc, Group: models.TagGroupEnumAction, } } createdCategory, err := s.resolver.Mutation().TagCategoryCreate(s.ctx, *input) if err != nil { s.t.Errorf("Error creating tag category: %s", err.Error()) return nil, err } return createdCategory, nil } func (s *testRunner) createTestTagEdit(operation models.OperationEnum, detailsInput *models.TagEditDetailsInput, editInput *models.EditInput) (*models.Edit, error) { s.t.Helper() if editInput == nil { input := models.EditInput{ Operation: operation, } editInput = &input } if detailsInput == nil { name := s.generateTagName() input := models.TagEditDetailsInput{ Name: &name, } detailsInput = &input } tagEditInput := models.TagEditInput{ Edit: editInput, Details: detailsInput, } createdEdit, err := s.resolver.Mutation().TagEdit(s.ctx, tagEditInput) if err != nil { s.t.Errorf("Error creating edit: %s", err.Error()) return nil, err } return createdEdit, nil } func (s *testRunner) createTestStudioEdit(operation models.OperationEnum, detailsInput *models.StudioEditDetailsInput, editInput *models.EditInput) (*models.Edit, error) { s.t.Helper() if editInput == nil { input := models.EditInput{ Operation: operation, } editInput = &input } if detailsInput == nil { name := s.generateStudioName() input := models.StudioEditDetailsInput{ Name: &name, } detailsInput = &input } studioEditInput := models.StudioEditInput{ Edit: editInput, Details: detailsInput, } createdEdit, err := s.resolver.Mutation().StudioEdit(s.ctx, studioEditInput) if err != nil { s.t.Errorf("Error creating edit: %s", err.Error()) return nil, err } return createdEdit, nil } func (s *testRunner) applyEdit(id uuid.UUID) (*models.Edit, error) { s.t.Helper() input := models.ApplyEditInput{ ID: id, } appliedEdit, err := s.resolver.Mutation().ApplyEdit(s.ctx, input) if err != nil { s.t.Errorf("Error applying edit: %s", err.Error()) return nil, err } return appliedEdit, nil } func (s *testRunner) getEditTagDetails(input *models.Edit) *models.TagEdit { s.t.Helper() r := s.resolver.Edit() details, _ := r.Details(s.ctx, input) tagDetails := details.(*models.TagEdit) return tagDetails } func (s *testRunner) getEditTagTarget(input *models.Edit) *models.Tag { s.t.Helper() r := s.resolver.Edit() target, _ := r.Target(s.ctx, input) tagTarget := target.(*models.Tag) return tagTarget } func (s *testRunner) getEditStudioDetails(input *models.Edit) *models.StudioEdit { s.t.Helper() r := s.resolver.Edit() details, _ := r.Details(s.ctx, input) tagDetails := details.(*models.StudioEdit) return tagDetails } func (s *testRunner) getEditStudioTarget(input *models.Edit) *models.Studio { s.t.Helper() r := s.resolver.Edit() target, _ := r.Target(s.ctx, input) tagTarget := target.(*models.Studio) return tagTarget } func oneNil(l interface{}, r interface{}) bool { return l != r && (l == nil || r == nil) } func bothNil(l interface{}, r interface{}) bool { return l == nil && r == nil } func (s *testRunner) verifyEditOperation(operation string, edit *models.Edit) { if edit.Operation != operation { s.fieldMismatch(operation, edit.Operation, "Operation") } } func (s *testRunner) verifyEditStatus(status string, edit *models.Edit) { if edit.Status != status { s.fieldMismatch(status, edit.Status, "Status") } } func (s *testRunner) verifyEditApplication(applied bool, edit *models.Edit) { if edit.Applied != applied { s.fieldMismatch(applied, edit.Applied, "Applied") } } func (s *testRunner) verifyEditTargetType(targetType string, edit *models.Edit) { if edit.TargetType != targetType { s.fieldMismatch(targetType, edit.TargetType, "TargetType") } } func (s *testRunner) verifyAppliedPerformerEdit(edit *models.Edit) { s.verifyEditOperation(models.OperationEnumModify.String(), edit) s.verifyEditStatus(models.VoteStatusEnumImmediateAccepted.String(), edit) s.verifyEditTargetType(models.TargetTypeEnumPerformer.String(), edit) s.verifyEditApplication(true, edit) } func (s *testRunner) verifyAppliedSceneEdit(edit *models.Edit) { s.verifyEditOperation(models.OperationEnumModify.String(), edit) s.verifyEditStatus(models.VoteStatusEnumImmediateAccepted.String(), edit) s.verifyEditTargetType(models.TargetTypeEnumScene.String(), edit) s.verifyEditApplication(true, edit) } func (s *testRunner) createTestPerformerEdit(operation models.OperationEnum, detailsInput *models.PerformerEditDetailsInput, editInput *models.EditInput, options *models.PerformerEditOptionsInput) (*models.Edit, error) { s.t.Helper() if editInput == nil { input := models.EditInput{ Operation: operation, } editInput = &input } if detailsInput == nil { name := s.generatePerformerName() input := models.PerformerEditDetailsInput{ Name: &name, } detailsInput = &input } performerEditInput := models.PerformerEditInput{ Edit: editInput, Details: detailsInput, Options: options, } createdEdit, err := s.resolver.Mutation().PerformerEdit(s.ctx, performerEditInput) if err != nil { s.t.Errorf("Error creating edit: %s", err.Error()) return nil, err } return createdEdit, nil } func (s *testRunner) getEditPerformerDetails(input *models.Edit) *models.PerformerEdit { s.t.Helper() r := s.resolver.Edit() details, _ := r.Details(s.ctx, input) performerDetails := details.(*models.PerformerEdit) return performerDetails } func (s *testRunner) getEditPerformerTarget(input *models.Edit) *models.Performer { s.t.Helper() r := s.resolver.Edit() target, _ := r.Target(s.ctx, input) performerTarget := target.(*models.Performer) return performerTarget } func (s *testRunner) createPerformerEditDetailsInput() *models.PerformerEditDetailsInput { name := s.generatePerformerName() disambiguation := "Dis Ambiguation" gender := models.GenderEnumFemale ethnicity := models.EthnicityEnumCaucasian eyecolor := models.EyeColorEnumBlue haircolor := models.HairColorEnumAuburn country := "Some Country" height := 160 hip := 23 waist := 24 band := 25 cup := "DD" breasttype := models.BreastTypeEnumNatural careerstart := 2019 careerend := 2020 tattoodesc := "Tatto Desc" birthdate := "2000-02-03" deathdate := "2024-01-02" site, err := s.createTestSite(nil) if err != nil { return nil } return &models.PerformerEditDetailsInput{ Name: &name, Disambiguation: &disambiguation, Aliases: []string{"Alias1"}, Gender: &gender, Urls: []models.URL{ { URL: "http://example.org", SiteID: site.ID, }, }, Birthdate: &birthdate, Deathdate: &deathdate, Ethnicity: ðnicity, Country: &country, EyeColor: &eyecolor, HairColor: &haircolor, Height: &height, HipSize: &hip, WaistSize: &waist, BandSize: &band, CupSize: &cup, BreastType: &breasttype, CareerStartYear: &careerstart, CareerEndYear: &careerend, Tattoos: []models.BodyModificationInput{ { Location: "Wrist", Description: &tattoodesc, }, }, Piercings: []models.BodyModificationInput{ { Location: "Ears", }, }, } } func (s *testRunner) createFullSceneCreateInput() *models.SceneCreateInput { title := s.generateSceneName() details := "Details" date := "2000-02-03" production_date := "2000-01-09" duration := 123 director := "Director" code := "SomeCode" site, err := s.createTestSite(nil) if err != nil { return nil } return &models.SceneCreateInput{ Title: &title, Details: &details, Urls: []models.URL{ { URL: "http://example.org", SiteID: site.ID, }, }, Date: date, ProductionDate: &production_date, Fingerprints: []models.FingerprintEditInput{ s.generateSceneFingerprint(nil), }, Duration: &duration, Director: &director, Code: &code, } } func (s *testRunner) createSceneEditDetailsInput() *models.SceneEditDetailsInput { title := s.generateSceneName() details := "Details" date := "2000-02-03" production_date := "2000-01-09" duration := 123 director := "Director" code := "SomeCode" site, err := s.createTestSite(nil) if err != nil { return nil } return &models.SceneEditDetailsInput{ Title: &title, Details: &details, Urls: []models.URL{ { URL: "http://example.org", SiteID: site.ID, }, }, Date: &date, ProductionDate: &production_date, Duration: &duration, Director: &director, Code: &code, } } func (s *testRunner) createFullSceneEditDetailsInput() *models.SceneEditDetailsInput { createdPerformer, err := s.createTestPerformer(nil) if err != nil { s.t.Errorf("Error creating performer: %s", err.Error()) return nil } createdTag, err := s.createTestTag(nil) if err != nil { s.t.Errorf("Error creating tag: %s", err.Error()) return nil } title := s.generateSceneName() details := "Details" date := "2000-02-03" production_date := "2000-01-09" duration := 123 director := "Director" code := "SomeCode" as := "Alias" site, err := s.createTestSite(nil) if err != nil { return nil } return &models.SceneEditDetailsInput{ Title: &title, Details: &details, Urls: []models.URL{ { URL: "http://example.org", SiteID: site.ID, }, }, Date: &date, ProductionDate: &production_date, Performers: []models.PerformerAppearanceInput{ { PerformerID: createdPerformer.UUID(), As: &as, }, }, TagIds: []uuid.UUID{ createdTag.UUID(), }, Duration: &duration, Director: &director, Code: &code, } } func (s *testRunner) createTestSceneEdit(operation models.OperationEnum, detailsInput *models.SceneEditDetailsInput, editInput *models.EditInput) (*models.Edit, error) { s.t.Helper() if editInput == nil { input := models.EditInput{ Operation: operation, } editInput = &input } if detailsInput == nil { title := s.generateSceneName() input := models.SceneEditDetailsInput{ Title: &title, } detailsInput = &input } sceneEditInput := models.SceneEditInput{ Edit: editInput, Details: detailsInput, } createdEdit, err := s.resolver.Mutation().SceneEdit(s.ctx, sceneEditInput) if err != nil { s.t.Errorf("Error creating edit: %s", err.Error()) return nil, err } return createdEdit, nil } func (s *testRunner) getEditSceneDetails(input *models.Edit) *models.SceneEdit { s.t.Helper() r := s.resolver.Edit() details, _ := r.Details(s.ctx, input) sceneDetails := details.(*models.SceneEdit) return sceneDetails } func (s *testRunner) getEditSceneTarget(input *models.Edit) *models.Scene { s.t.Helper() r := s.resolver.Edit() target, _ := r.Target(s.ctx, input) sceneTarget := target.(*models.Scene) return sceneTarget } func (s *testRunner) generateSiteName() string { siteSuffix += 1 return "site-" + strconv.Itoa(siteSuffix) } func (s *testRunner) createTestSite(input *models.SiteCreateInput) (*models.Site, error) { s.t.Helper() if input == nil { name := s.generateSiteName() desc := "Description for " + name input = &models.SiteCreateInput{ Name: name, Description: &desc, ValidTypes: []models.ValidSiteTypeEnum{models.ValidSiteTypeEnumScene}, } } createdSite, err := s.resolver.Mutation().SiteCreate(s.ctx, *input) if err != nil { s.t.Errorf("Error creating site: %s", err.Error()) return nil, err } return createdSite, nil } func (s *testRunner) compareSiteURLs(input []models.URL, output []siteURL) { var convertedURLs []models.URL for _, url := range output { convertedURLs = append(convertedURLs, models.URL{ URL: url.URL, SiteID: uuid.FromStringOrNil(url.Site.ID), }) } assert.Equal(s.t, input, convertedURLs) } func comparePerformers(input []models.PerformerAppearanceInput, performers []performerAppearance) bool { if len(performers) != len(input) { return false } for i, v := range performers { performerID := v.Performer.ID if performerID != input[i].PerformerID.String() { return false } if v.As != input[i].As { if v.As == nil || input[i].As == nil { return false } if *v.As != *input[i].As { return false } } } return true } func comparePerformersInput(input, performers []models.PerformerAppearanceInput) bool { if len(performers) != len(input) { return false } for i, v := range performers { performerID := v.PerformerID if performerID != input[i].PerformerID { return false } if v.As != input[i].As { if v.As == nil || input[i].As == nil { return false } if *v.As != *input[i].As { return false } } } return true } func compareTags(tagIDs []uuid.UUID, tags []idObject) bool { if len(tags) != len(tagIDs) { return false } for i, v := range tags { tagID := v.ID if tagID != tagIDs[i].String() { return false } } return true } func compareFingerprints(input []models.FingerprintEditInput, fingerprints []fingerprint) bool { if len(input) != len(fingerprints) { return false } for i, v := range fingerprints { if input[i].Algorithm != v.Algorithm || input[i].Hash.Hex() != v.Hash { return false } } return true } func compareFingerprintsInput(input, fingerprints []models.FingerprintEditInput) bool { if len(input) != len(fingerprints) { return false } for i, v := range fingerprints { if input[i].Algorithm != v.Algorithm || input[i].Hash != v.Hash { return false } } return true } func assertBodyMods(t *testing.T, input []models.BodyModificationInput, bodyMods []models.BodyModification, text string) { t.Helper() // Flatten input to strings inputStrs := make([]string, len(input)) for i, v := range input { desc := "" if v.Description != nil { desc = *v.Description } inputStrs[i] = v.Location + "|" + desc } // Flatten bodyMods to strings bodyModStrs := make([]string, len(bodyMods)) for i, v := range bodyMods { desc := "" if v.Description != nil { desc = *v.Description } bodyModStrs[i] = v.Location + "|" + desc } // Use ElementsMatch for order-independent comparison assert.ElementsMatch(t, inputStrs, bodyModStrs, text) } func (s *testRunner) getUserNotificationSubscriptions() ([]models.NotificationEnum, error) { return s.client.getNotificationSubscriptions() } ================================================ FILE: internal/api/loaders.go ================================================ package api import ( "context" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/dataloader" "github.com/stashapp/stash-box/internal/models" ) func tagList(ctx context.Context, tagIDs []uuid.UUID) ([]models.Tag, error) { if len(tagIDs) == 0 { return nil, nil } ret, errors := dataloader.For(ctx).TagByID.LoadAll(tagIDs) for _, err := range errors { if err != nil { return nil, err } } var tags []models.Tag for _, tag := range ret { if tag != nil { tags = append(tags, *tag) } } return tags, nil } func imageList(ctx context.Context, imageIDs []uuid.UUID) ([]models.Image, error) { if len(imageIDs) == 0 { return nil, nil } res, errors := dataloader.For(ctx).ImageByID.LoadAll(imageIDs) for _, err := range errors { if err != nil { return nil, err } } var images []models.Image for _, image := range res { if image != nil { images = append(images, *image) } } return images, nil } ================================================ FILE: internal/api/notification_integration_test.go ================================================ //go:build integration package api_test import ( "context" "testing" "time" "github.com/stashapp/stash-box/internal/auth" "github.com/stashapp/stash-box/internal/models" "github.com/stretchr/testify/assert" ) type notificationTestRunner struct { testRunner } func createNotificationTestRunner(t *testing.T) *notificationTestRunner { return ¬ificationTestRunner{ testRunner: *asEdit(t), } } // testNotificationOnCommentOwnEdit tests that a notification is created when someone comments on the user's own edit func (s *notificationTestRunner) testNotificationOnCommentOwnEdit() { // Create an edit as the main test user createdEdit, err := s.createTestTagEdit(models.OperationEnumCreate, nil, nil) assert.NoError(s.t, err) // Subscribe to comment notifications subscriptions := []models.NotificationEnum{ models.NotificationEnumCommentOwnEdit, } _, err = s.client.updateNotificationSubscriptions(subscriptions) assert.NoError(s.t, err) // Get initial unread count initialUnreadCount, err := s.client.getUnreadNotificationCount() assert.NoError(s.t, err) // Create another user and have them comment on the edit commenterUser, err := s.createTestUser(nil, []models.RoleEnum{models.RoleEnumEdit}) assert.NoError(s.t, err) commenterCtx := context.WithValue(s.ctx, auth.ContextUser, commenterUser) commentText := "Test comment on edit" _, err = s.resolver.Mutation().EditComment(commenterCtx, models.EditCommentInput{ ID: createdEdit.ID, Comment: commentText, }) assert.NoError(s.t, err) // Small delay to ensure notification is created time.Sleep(100 * time.Millisecond) // Verify unread count increased newUnreadCount, err := s.client.getUnreadNotificationCount() assert.NoError(s.t, err) assert.True(s.t, newUnreadCount > initialUnreadCount, "Unread count should have increased after comment") // Query notifications to verify the notification was created result, err := s.client.queryNotifications(models.QueryNotificationsInput{ Page: 1, PerPage: 25, UnreadOnly: pointerTo(true), }) assert.NoError(s.t, err) assert.True(s.t, len(result.Notifications) > 0, "Should have at least one unread notification") // Find the notification we just created foundNotification := false for _, notification := range result.Notifications { if !notification.Read { foundNotification = true break } } assert.True(s.t, foundNotification, "Should find an unread notification") } // testNotificationOnDownvoteOwnEdit tests that a notification is created when someone downvotes the user's edit func (s *notificationTestRunner) testNotificationOnDownvoteOwnEdit() { // Create an edit as the main test user createdEdit, err := s.createTestTagEdit(models.OperationEnumCreate, nil, nil) assert.NoError(s.t, err) // Subscribe to downvote notifications subscriptions := []models.NotificationEnum{ models.NotificationEnumDownvoteOwnEdit, } _, err = s.client.updateNotificationSubscriptions(subscriptions) assert.NoError(s.t, err) // Get initial unread count initialUnreadCount, err := s.client.getUnreadNotificationCount() assert.NoError(s.t, err) // Create a user with vote role and have them downvote the edit voterUser, err := s.createTestUser(nil, []models.RoleEnum{models.RoleEnumVote}) assert.NoError(s.t, err) voterCtx := context.WithValue(s.ctx, auth.ContextUser, voterUser) _, err = s.resolver.Mutation().EditVote(voterCtx, models.EditVoteInput{ ID: createdEdit.ID, Vote: models.VoteTypeEnumReject, }) assert.NoError(s.t, err) // Small delay to ensure notification is created time.Sleep(100 * time.Millisecond) // Verify unread count increased newUnreadCount, err := s.client.getUnreadNotificationCount() assert.NoError(s.t, err) assert.True(s.t, newUnreadCount > initialUnreadCount, "Unread count should have increased after downvote") // Query notifications to verify result, err := s.client.queryNotifications(models.QueryNotificationsInput{ Page: 1, PerPage: 25, UnreadOnly: pointerTo(true), }) assert.NoError(s.t, err) assert.True(s.t, len(result.Notifications) > 0, "Should have at least one unread notification") } // testNotificationOnFailedOwnEdit tests that a notification is NOT created when the user cancels their own edit func (s *notificationTestRunner) testNotificationOnFailedOwnEdit() { // Create an edit as the main test user createdEdit, err := s.createTestTagEdit(models.OperationEnumCreate, nil, nil) assert.NoError(s.t, err) // Subscribe to failed edit notifications subscriptions := []models.NotificationEnum{ models.NotificationEnumFailedOwnEdit, } _, err = s.client.updateNotificationSubscriptions(subscriptions) assert.NoError(s.t, err) // Get initial unread count initialUnreadCount, err := s.client.getUnreadNotificationCount() assert.NoError(s.t, err) // Cancel the edit (which should NOT trigger a notification for self-cancellation) _, err = s.resolver.Mutation().CancelEdit(s.ctx, models.CancelEditInput{ ID: createdEdit.ID, }) assert.NoError(s.t, err) // Small delay to ensure any notification would have been created time.Sleep(100 * time.Millisecond) // Verify unread count did NOT increase (no notification for self-cancellation) newUnreadCount, err := s.client.getUnreadNotificationCount() assert.NoError(s.t, err) assert.Equal(s.t, initialUnreadCount, newUnreadCount, "Unread count should NOT change when user cancels their own edit") } // testNotificationOnAdminCancelEdit tests that a notification IS created when an admin cancels/rejects the user's edit func (s *notificationTestRunner) testNotificationOnAdminCancelEdit() { // Create an edit as the main test user createdEdit, err := s.createTestTagEdit(models.OperationEnumCreate, nil, nil) assert.NoError(s.t, err) // Subscribe to failed edit notifications subscriptions := []models.NotificationEnum{ models.NotificationEnumFailedOwnEdit, } _, err = s.client.updateNotificationSubscriptions(subscriptions) assert.NoError(s.t, err) // Get initial unread count initialUnreadCount, err := s.client.getUnreadNotificationCount() assert.NoError(s.t, err) // Use the existing admin user to cancel the edit adminCtx := context.WithValue(s.ctx, auth.ContextUser, userDB.admin) adminCtx = context.WithValue(adminCtx, auth.ContextRoles, userDB.adminRoles) _, err = s.resolver.Mutation().CancelEdit(adminCtx, models.CancelEditInput{ ID: createdEdit.ID, }) assert.NoError(s.t, err) // Small delay to ensure notification is created time.Sleep(100 * time.Millisecond) // Verify unread count increased newUnreadCount, err := s.client.getUnreadNotificationCount() assert.NoError(s.t, err) assert.True(s.t, newUnreadCount > initialUnreadCount, "Unread count should have increased after admin cancellation") // Query notifications to verify result, err := s.client.queryNotifications(models.QueryNotificationsInput{ Page: 1, PerPage: 25, UnreadOnly: pointerTo(true), }) assert.NoError(s.t, err) assert.True(s.t, len(result.Notifications) > 0, "Should have at least one unread notification") } // testMarkSpecificNotificationRead tests marking a specific notification as read func (s *notificationTestRunner) testMarkSpecificNotificationRead() { // First, clear all existing notifications by marking them all as read _, _ = s.client.markNotificationsRead(nil) time.Sleep(100 * time.Millisecond) // Create an edit and trigger a notification createdEdit, err := s.createTestTagEdit(models.OperationEnumCreate, nil, nil) assert.NoError(s.t, err) // Subscribe to comment notifications subscriptions := []models.NotificationEnum{ models.NotificationEnumCommentOwnEdit, } _, err = s.client.updateNotificationSubscriptions(subscriptions) assert.NoError(s.t, err) // Create a comment to trigger notification - we need the comment ID for marking as read commenterUser, err := s.createTestUser(nil, []models.RoleEnum{models.RoleEnumEdit}) assert.NoError(s.t, err) commenterCtx := context.WithValue(s.ctx, auth.ContextUser, commenterUser) editWithComment, err := s.resolver.Mutation().EditComment(commenterCtx, models.EditCommentInput{ ID: createdEdit.ID, Comment: "Test comment", }) assert.NoError(s.t, err) // Get the comment ID from the edit comments, err := s.resolver.Edit().Comments(s.ctx, editWithComment) assert.NoError(s.t, err) assert.True(s.t, len(comments) > 0, "Should have at least one comment") commentID := comments[0].ID // Wait for notification to be created (increased timeout for CI environments) time.Sleep(100 * time.Millisecond) // Get unread count before marking as read unreadCountBefore, err := s.client.getUnreadNotificationCount() assert.NoError(s.t, err) assert.True(s.t, unreadCountBefore >= 1, "Should have at least one unread notification") // Mark the specific notification as read using the comment ID success, err := s.client.markNotificationsRead(&models.MarkNotificationReadInput{ Type: models.NotificationEnumCommentOwnEdit, ID: commentID, }) assert.NoError(s.t, err) assert.True(s.t, success, "Marking notification as read should succeed") time.Sleep(100 * time.Millisecond) // Verify unread count decreased unreadCountAfter, err := s.client.getUnreadNotificationCount() assert.NoError(s.t, err) assert.True(s.t, unreadCountAfter < unreadCountBefore, "Unread count should have decreased after marking notification as read") // Query unread notifications and verify the count decreased resultAfter, err := s.client.queryNotifications(models.QueryNotificationsInput{ Page: 1, PerPage: 100, UnreadOnly: pointerTo(true), }) assert.NoError(s.t, err) assert.True(s.t, len(resultAfter.Notifications) < unreadCountBefore, "Should have fewer unread notifications after marking one as read") } // testMarkAllNotificationsRead tests marking all notifications as read func (s *notificationTestRunner) testMarkAllNotificationsRead() { // Subscribe to multiple notification types subscriptions := []models.NotificationEnum{ models.NotificationEnumCommentOwnEdit, models.NotificationEnumDownvoteOwnEdit, models.NotificationEnumFailedOwnEdit, } _, err := s.client.updateNotificationSubscriptions(subscriptions) assert.NoError(s.t, err) // Create multiple edits and trigger multiple notifications for i := 0; i < 3; i++ { createdEdit, err := s.createTestTagEdit(models.OperationEnumCreate, nil, nil) assert.NoError(s.t, err) // Create a comment to trigger notification commenterUser, err := s.createTestUser(nil, []models.RoleEnum{models.RoleEnumEdit}) assert.NoError(s.t, err) commenterCtx := context.WithValue(s.ctx, auth.ContextUser, commenterUser) _, err = s.resolver.Mutation().EditComment(commenterCtx, models.EditCommentInput{ ID: createdEdit.ID, Comment: "Test comment", }) assert.NoError(s.t, err) } // Wait for all notifications to be created (multiple notifications, so longer wait) time.Sleep(200 * time.Millisecond) // Verify we have unread notifications unreadCountBefore, err := s.client.getUnreadNotificationCount() assert.NoError(s.t, err) assert.True(s.t, unreadCountBefore >= 3, "Should have at least 3 unread notifications") // Mark all notifications as read by passing nil success, err := s.client.markNotificationsRead(nil) assert.NoError(s.t, err) assert.True(s.t, success, "Marking all notifications as read should succeed") // Verify unread count is now 0 unreadCountAfter, err := s.client.getUnreadNotificationCount() assert.NoError(s.t, err) assert.Equal(s.t, unreadCountAfter, 0, "Unread count should be 0 after marking all as read") // Query unread notifications and verify none are returned result, err := s.client.queryNotifications(models.QueryNotificationsInput{ Page: 1, PerPage: 25, UnreadOnly: pointerTo(true), }) assert.NoError(s.t, err) assert.Equal(s.t, len(result.Notifications), 0, "Should have no unread notifications after marking all as read") } // Helper function to create a pointer to a boolean func pointerTo[T any](v T) *T { return &v } func TestNotificationOnCommentOwnEdit(t *testing.T) { pt := createNotificationTestRunner(t) pt.testNotificationOnCommentOwnEdit() } func TestNotificationOnDownvoteOwnEdit(t *testing.T) { pt := createNotificationTestRunner(t) pt.testNotificationOnDownvoteOwnEdit() } func TestNotificationOnFailedOwnEdit(t *testing.T) { pt := createNotificationTestRunner(t) pt.testNotificationOnFailedOwnEdit() } func TestNotificationOnAdminCancelEdit(t *testing.T) { pt := createNotificationTestRunner(t) pt.testNotificationOnAdminCancelEdit() } func TestMarkSpecificNotificationRead(t *testing.T) { pt := createNotificationTestRunner(t) pt.testMarkSpecificNotificationRead() } func TestMarkAllNotificationsRead(t *testing.T) { pt := createNotificationTestRunner(t) pt.testMarkAllNotificationsRead() } // testNotificationSubscriptionRoleEnforcement tests that READ users can only subscribe to favorite notification types func (s *notificationTestRunner) testNotificationSubscriptionRoleEnforcement() { // Test 1: READ user can subscribe to favorite notification types readRunner := asRead(s.t) favoriteSubscriptions := []models.NotificationEnum{ models.NotificationEnumFavoritePerformerScene, models.NotificationEnumFavoritePerformerEdit, models.NotificationEnumFavoriteStudioScene, models.NotificationEnumFavoriteStudioEdit, } success, err := readRunner.client.updateNotificationSubscriptions(favoriteSubscriptions) assert.NoError(s.t, err) assert.True(s.t, success, "READ user should be able to subscribe to favorite notification types") // Verify subscriptions were actually set currentSubscriptions, err := readRunner.getUserNotificationSubscriptions() assert.NoError(s.t, err) assert.ElementsMatch(s.t, favoriteSubscriptions, currentSubscriptions, "READ user should have all favorite subscriptions set") // Test 2: READ user attempts to subscribe to both favorite and non-favorite types // Non-favorite types should be silently filtered out mixedSubscriptions := []models.NotificationEnum{ models.NotificationEnumFavoritePerformerScene, // favorite - should be kept models.NotificationEnumFavoriteStudioEdit, // favorite - should be kept models.NotificationEnumCommentOwnEdit, // non-favorite - should be filtered models.NotificationEnumDownvoteOwnEdit, // non-favorite - should be filtered models.NotificationEnumUpdatedEdit, // non-favorite - should be filtered models.NotificationEnumCommentCommentedEdit, // non-favorite - should be filtered models.NotificationEnumFingerprintedSceneEdit, // non-favorite - should be filtered } success, err = readRunner.client.updateNotificationSubscriptions(mixedSubscriptions) assert.NoError(s.t, err) assert.True(s.t, success, "updateNotificationSubscriptions should succeed for READ user") // Verify only favorite subscriptions were set currentSubscriptions, err = readRunner.getUserNotificationSubscriptions() assert.NoError(s.t, err) expectedSubscriptions := []models.NotificationEnum{ models.NotificationEnumFavoritePerformerScene, models.NotificationEnumFavoriteStudioEdit, } assert.ElementsMatch(s.t, expectedSubscriptions, currentSubscriptions, "READ user should only have favorite subscriptions set") // Test 3: EDIT user can subscribe to all notification types including non-favorites editRunner := asEdit(s.t) allSubscriptions := []models.NotificationEnum{ models.NotificationEnumFavoritePerformerScene, models.NotificationEnumFavoriteStudioEdit, models.NotificationEnumCommentOwnEdit, models.NotificationEnumDownvoteOwnEdit, models.NotificationEnumUpdatedEdit, models.NotificationEnumFailedOwnEdit, models.NotificationEnumCommentCommentedEdit, models.NotificationEnumCommentVotedEdit, models.NotificationEnumFingerprintedSceneEdit, } success, err = editRunner.client.updateNotificationSubscriptions(allSubscriptions) assert.NoError(s.t, err) assert.True(s.t, success, "EDIT user should be able to subscribe to all notification types") // Verify all subscriptions were set currentSubscriptions, err = editRunner.getUserNotificationSubscriptions() assert.NoError(s.t, err) assert.ElementsMatch(s.t, allSubscriptions, currentSubscriptions, "EDIT user should have all subscriptions set") } func TestNotificationSubscriptionRoleEnforcement(t *testing.T) { pt := createNotificationTestRunner(t) pt.testNotificationSubscriptionRoleEnforcement() } // testQueryNotificationsPagination tests that pagination works correctly for queryNotifications func (s *notificationTestRunner) testQueryNotificationsPagination() { // First, mark all existing notifications as read to start fresh _, _ = s.client.markNotificationsRead(nil) time.Sleep(100 * time.Millisecond) // Subscribe to comment notifications subscriptions := []models.NotificationEnum{ models.NotificationEnumCommentOwnEdit, } _, err := s.client.updateNotificationSubscriptions(subscriptions) assert.NoError(s.t, err) // Create 5 edits and have different users comment on them to generate 5 notifications for i := 0; i < 5; i++ { createdEdit, err := s.createTestTagEdit(models.OperationEnumCreate, nil, nil) assert.NoError(s.t, err) commenterUser, err := s.createTestUser(nil, []models.RoleEnum{models.RoleEnumEdit}) assert.NoError(s.t, err) commenterCtx := context.WithValue(s.ctx, auth.ContextUser, commenterUser) _, err = s.resolver.Mutation().EditComment(commenterCtx, models.EditCommentInput{ ID: createdEdit.ID, Comment: "Test comment", }) assert.NoError(s.t, err) } // Wait for all notifications to be created time.Sleep(200 * time.Millisecond) // Test pagination with perPage=2 perPage := 2 // Fetch page 1 page1Result, err := s.client.queryNotifications(models.QueryNotificationsInput{ Page: 1, PerPage: perPage, UnreadOnly: pointerTo(true), }) assert.NoError(s.t, err) assert.Equal(s.t, 5, page1Result.Count, "Total count should be 5") assert.Equal(s.t, 2, len(page1Result.Notifications), "Page 1 should have 2 notifications") // Fetch page 2 page2Result, err := s.client.queryNotifications(models.QueryNotificationsInput{ Page: 2, PerPage: perPage, UnreadOnly: pointerTo(true), }) assert.NoError(s.t, err) assert.Equal(s.t, 5, page2Result.Count, "Total count should still be 5") assert.Equal(s.t, 2, len(page2Result.Notifications), "Page 2 should have 2 notifications") // Fetch page 3 page3Result, err := s.client.queryNotifications(models.QueryNotificationsInput{ Page: 3, PerPage: perPage, UnreadOnly: pointerTo(true), }) assert.NoError(s.t, err) assert.Equal(s.t, 5, page3Result.Count, "Total count should still be 5") assert.Equal(s.t, 1, len(page3Result.Notifications), "Page 3 should have 1 notification") // Verify no overlap between pages by comparing timestamps // Since notifications are ordered by created_at DESC, page 1 should have newer or equal timestamps than page 2 if len(page1Result.Notifications) > 0 && len(page2Result.Notifications) > 0 { lastPage1Time := page1Result.Notifications[len(page1Result.Notifications)-1].Created firstPage2Time := page2Result.Notifications[0].Created // String comparison works for ISO8601 timestamps assert.True(s.t, lastPage1Time >= firstPage2Time, "Page 1 last notification should be newer or equal to page 2 first notification") } // Test page beyond available data page4Result, err := s.client.queryNotifications(models.QueryNotificationsInput{ Page: 4, PerPage: perPage, UnreadOnly: pointerTo(true), }) assert.NoError(s.t, err) assert.Equal(s.t, 5, page4Result.Count, "Total count should still be 5") assert.Equal(s.t, 0, len(page4Result.Notifications), "Page 4 should have 0 notifications") } func TestQueryNotificationsPagination(t *testing.T) { pt := createNotificationTestRunner(t) pt.testQueryNotificationsPagination() } // testQueryNotificationsTypeFilter tests that the type filter works correctly func (s *notificationTestRunner) testQueryNotificationsTypeFilter() { // First, mark all existing notifications as read to have a clean slate _, _ = s.client.markNotificationsRead(nil) time.Sleep(100 * time.Millisecond) // Subscribe to multiple notification types subscriptions := []models.NotificationEnum{ models.NotificationEnumCommentOwnEdit, models.NotificationEnumDownvoteOwnEdit, } _, err := s.client.updateNotificationSubscriptions(subscriptions) assert.NoError(s.t, err) // Create an edit to trigger notifications createdEdit, err := s.createTestTagEdit(models.OperationEnumCreate, nil, nil) assert.NoError(s.t, err) // Create a comment to trigger COMMENT_OWN_EDIT notification commenterUser, err := s.createTestUser(nil, []models.RoleEnum{models.RoleEnumEdit}) assert.NoError(s.t, err) commenterCtx := context.WithValue(s.ctx, auth.ContextUser, commenterUser) _, err = s.resolver.Mutation().EditComment(commenterCtx, models.EditCommentInput{ ID: createdEdit.ID, Comment: "Test comment", }) assert.NoError(s.t, err) // Create a downvote to trigger DOWNVOTE_OWN_EDIT notification voterUser, err := s.createTestUser(nil, []models.RoleEnum{models.RoleEnumVote}) assert.NoError(s.t, err) voterCtx := context.WithValue(s.ctx, auth.ContextUser, voterUser) _, err = s.resolver.Mutation().EditVote(voterCtx, models.EditVoteInput{ ID: createdEdit.ID, Vote: models.VoteTypeEnumReject, }) assert.NoError(s.t, err) // Wait for notifications to be created time.Sleep(200 * time.Millisecond) // Query all notifications (no type filter) allResult, err := s.client.queryNotifications(models.QueryNotificationsInput{ Page: 1, PerPage: 25, UnreadOnly: pointerTo(true), }) assert.NoError(s.t, err) assert.Equal(s.t, 2, allResult.Count, "Should have exactly 2 notifications total") assert.Equal(s.t, 2, len(allResult.Notifications), "Should return exactly 2 notifications") // Query only COMMENT_OWN_EDIT notifications commentNotificationType := models.NotificationEnumCommentOwnEdit commentResult, err := s.client.queryNotifications(models.QueryNotificationsInput{ Page: 1, PerPage: 25, Type: &commentNotificationType, UnreadOnly: pointerTo(true), }) assert.NoError(s.t, err) assert.Equal(s.t, 1, commentResult.Count, "Should have exactly 1 COMMENT_OWN_EDIT notification") assert.Equal(s.t, 1, len(commentResult.Notifications), "Should return exactly 1 COMMENT_OWN_EDIT notification") // Query only DOWNVOTE_OWN_EDIT notifications downvoteNotificationType := models.NotificationEnumDownvoteOwnEdit downvoteResult, err := s.client.queryNotifications(models.QueryNotificationsInput{ Page: 1, PerPage: 25, Type: &downvoteNotificationType, UnreadOnly: pointerTo(true), }) assert.NoError(s.t, err) assert.Equal(s.t, 1, downvoteResult.Count, "Should have exactly 1 DOWNVOTE_OWN_EDIT notification") assert.Equal(s.t, 1, len(downvoteResult.Notifications), "Should return exactly 1 DOWNVOTE_OWN_EDIT notification") // Verify the sum of filtered notifications equals the total totalFiltered := commentResult.Count + downvoteResult.Count assert.Equal(s.t, allResult.Count, totalFiltered, "Sum of filtered notifications should equal total notifications") } func TestQueryNotificationsTypeFilter(t *testing.T) { pt := createNotificationTestRunner(t) pt.testQueryNotificationsTypeFilter() } // testNotificationOnFavoriteStudioScene tests that a FAVORITE_STUDIO_SCENE notification is created // when a scene is created for a studio that the user has favorited and the edit is approved via voting func (s *notificationTestRunner) testNotificationOnFavoriteStudioScene() { // Create a studio using the admin user adminRunner := asAdmin(s.t) studio, err := adminRunner.createTestStudio(nil) assert.NoError(s.t, err) studioID := studio.UUID() // Create a subscriber user who will favorite the studio subscriberUser, err := s.createTestUser(nil, []models.RoleEnum{models.RoleEnumEdit}) assert.NoError(s.t, err) // Create a runner for the subscriber to make GraphQL calls subscriberRunner := createTestRunner(s.t, subscriberUser, []models.RoleEnum{models.RoleEnumEdit}) // Subscriber favorites the studio _, err = subscriberRunner.client.favoriteStudio(studioID, true) assert.NoError(s.t, err) // Subscriber subscribes to FAVORITE_STUDIO_SCENE notifications subscriptions := []models.NotificationEnum{ models.NotificationEnumFavoriteStudioScene, } _, err = subscriberRunner.client.updateNotificationSubscriptions(subscriptions) assert.NoError(s.t, err) // Create an editor user who will submit the scene edit editorUser, err := s.createTestUser(nil, []models.RoleEnum{models.RoleEnumEdit}) assert.NoError(s.t, err) editorRunner := createTestRunner(s.t, editorUser, []models.RoleEnum{models.RoleEnumEdit}) // Editor creates a scene edit with the favorited studio title := editorRunner.generateSceneName() sceneEditDetailsInput := models.SceneEditDetailsInput{ Title: &title, StudioID: &studioID, } createdEdit, err := editorRunner.createTestSceneEdit(models.OperationEnumCreate, &sceneEditDetailsInput, nil) assert.NoError(s.t, err) // Have 3 voters vote to approve the edit (reaching the threshold) for i := 1; i <= 3; i++ { voterUser, err := s.createTestUser(nil, []models.RoleEnum{models.RoleEnumVote}) assert.NoError(s.t, err) voterCtx := context.WithValue(s.ctx, auth.ContextUser, voterUser) _, err = s.resolver.Mutation().EditVote(voterCtx, models.EditVoteInput{ ID: createdEdit.ID, Vote: models.VoteTypeEnumAccept, }) assert.NoError(s.t, err) } // Small delay to ensure notification is created (notifications are triggered asynchronously) time.Sleep(200 * time.Millisecond) // Query notifications and verify the notification type notificationType := models.NotificationEnumFavoriteStudioScene result, err := subscriberRunner.client.queryNotifications(models.QueryNotificationsInput{ Page: 1, PerPage: 25, Type: ¬ificationType, UnreadOnly: pointerTo(true), }) assert.NoError(s.t, err) assert.Equal(s.t, 1, len(result.Notifications), "Subscriber should have exactly one FAVORITE_STUDIO_SCENE notification") } func TestNotificationOnFavoriteStudioScene(t *testing.T) { pt := createNotificationTestRunner(t) pt.testNotificationOnFavoriteStudioScene() } ================================================ FILE: internal/api/performer_edit_integration_test.go ================================================ //go:build integration package api_test import ( "fmt" "testing" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" "github.com/stretchr/testify/assert" ) type performerEditTestRunner struct { testRunner } func contains(slice []uuid.UUID, item uuid.UUID) bool { for _, v := range slice { if v == item { return true } } return false } func createPerformerEditTestRunner(t *testing.T) *performerEditTestRunner { return &performerEditTestRunner{ testRunner: *asAdmin(t), } } func (s *performerEditTestRunner) compareBodyModifications(input []models.BodyModificationInput, actual []models.BodyModification) { assert.Equal(s.t, len(input), len(actual)) for i, inp := range input { assert.Equal(s.t, inp.Location, actual[i].Location) if inp.Description == nil { assert.Nil(s.t, actual[i].Description) } else { assert.Equal(s.t, *inp.Description, *actual[i].Description) } } } func (s *performerEditTestRunner) testCreatePerformerEdit() { performerEditDetailsInput := s.createPerformerEditDetailsInput() edit, err := s.createTestPerformerEdit(models.OperationEnumCreate, performerEditDetailsInput, nil, nil) assert.NoError(s.t, err) s.verifyCreatedPerformerEdit(*performerEditDetailsInput, edit) } func (s *performerEditTestRunner) verifyCreatedPerformerEdit(input models.PerformerEditDetailsInput, edit *models.Edit) { assert.True(s.t, edit.ID != uuid.Nil, "Expected created edit id to be non-zero") s.verifyEditOperation(models.OperationEnumCreate.String(), edit) s.verifyEditStatus(models.VoteStatusEnumPending.String(), edit) s.verifyEditTargetType(models.TargetTypeEnumPerformer.String(), edit) s.verifyEditApplication(false, edit) s.verifyPerformerEditDetails(input, edit) } func (s *performerEditTestRunner) testFindEditById() { createdEdit, err := s.createTestPerformerEdit(models.OperationEnumCreate, nil, nil, nil) assert.NoError(s.t, err) editID := createdEdit.ID edit, err := s.resolver.Query().FindEdit(s.ctx, editID) assert.NoError(s.t, err, "Error finding edit: %s") assert.NotNil(s.t, edit, "Did not find edit by id") } func (s *performerEditTestRunner) testModifyPerformerEdit() { existingName := "performerName" existingBirthdate := "1990-01-02" existingDeathdate := "2024-11-22" performerCreateInput := models.PerformerCreateInput{ Name: existingName, Birthdate: &existingBirthdate, Deathdate: &existingDeathdate, } createdPerformer, err := s.createTestPerformer(&performerCreateInput) assert.NoError(s.t, err) performerEditDetailsInput := s.createPerformerEditDetailsInput() id := createdPerformer.UUID() editInput := models.EditInput{ Operation: models.OperationEnumModify, ID: &id, } createdUpdateEdit, err := s.createTestPerformerEdit(models.OperationEnumModify, performerEditDetailsInput, &editInput, nil) assert.NoError(s.t, err) s.verifyUpdatedPerformerEdit(createdPerformer, *performerEditDetailsInput, createdUpdateEdit) } func (s *performerEditTestRunner) verifyUpdatedPerformerEdit(originalPerformer *performerOutput, input models.PerformerEditDetailsInput, edit *models.Edit) { s.verifyEditOperation(models.OperationEnumModify.String(), edit) s.verifyEditStatus(models.VoteStatusEnumPending.String(), edit) s.verifyEditTargetType(models.TargetTypeEnumPerformer.String(), edit) s.verifyEditApplication(false, edit) s.verifyPerformerEditDetails(input, edit) } func (s *performerEditTestRunner) verifyPerformerEditDetails(input models.PerformerEditDetailsInput, edit *models.Edit) { performerDetails := s.getEditPerformerDetails(edit) c := fieldComparator{r: &s.testRunner} c.strPtrStrPtr(input.Name, performerDetails.Name, "Name") c.strPtrStrPtr(input.Disambiguation, performerDetails.Disambiguation, "Disambiguation") c.strPtrStrPtr(input.Birthdate, performerDetails.Birthdate, "Birthdate") c.strPtrStrPtr(input.Deathdate, performerDetails.Deathdate, "Deathdate") assert.Equal(s.t, input.Aliases, performerDetails.AddedAliases) if input.Gender == nil { assert.Nil(s.t, performerDetails.Gender) } else { assert.True(s.t, input.Gender.IsValid() && (input.Gender.String() == *performerDetails.Gender)) } assert.Equal(s.t, input.Urls, performerDetails.AddedUrls) if input.Ethnicity == nil { assert.Nil(s.t, performerDetails.Ethnicity) } else { assert.True(s.t, input.Ethnicity.IsValid() && (input.Ethnicity.String() == *performerDetails.Ethnicity)) } if input.Country == nil { assert.Nil(s.t, performerDetails.Country) } else { assert.True(s.t, *input.Country == *performerDetails.Country) } if input.EyeColor == nil { assert.Nil(s.t, performerDetails.EyeColor) } else { assert.True(s.t, input.EyeColor.IsValid() && (input.EyeColor.String() == *performerDetails.EyeColor)) } if input.HairColor == nil { assert.Nil(s.t, performerDetails.HairColor) } else { assert.True(s.t, input.HairColor.IsValid() && (input.HairColor.String() == *performerDetails.HairColor)) } if input.Height == nil { assert.Nil(s.t, performerDetails.Height) } else { assert.True(s.t, *input.Height == *performerDetails.Height) } if input.BandSize == nil { assert.Nil(s.t, performerDetails.BandSize) } else { assert.True(s.t, *input.BandSize == *performerDetails.BandSize) } if input.WaistSize == nil { assert.Nil(s.t, performerDetails.WaistSize) } else { assert.True(s.t, *input.WaistSize == *performerDetails.WaistSize) } if input.HipSize == nil { assert.Nil(s.t, performerDetails.HipSize) } else { assert.True(s.t, *input.HipSize == *performerDetails.HipSize) } if input.CupSize == nil { assert.Nil(s.t, performerDetails.CupSize) } else { assert.True(s.t, *input.CupSize == *performerDetails.CupSize) } if input.BreastType == nil { assert.Nil(s.t, performerDetails.BreastType) } else { assert.True(s.t, input.BreastType.IsValid() && (input.BreastType.String() == *performerDetails.BreastType)) } if input.CareerStartYear == nil { assert.Nil(s.t, performerDetails.CareerStartYear) } else { assert.True(s.t, *input.CareerStartYear == *performerDetails.CareerStartYear) } if input.CareerEndYear == nil { assert.Nil(s.t, performerDetails.CareerEndYear) } else { assert.True(s.t, *input.CareerEndYear == *performerDetails.CareerEndYear) } s.compareBodyModifications(input.Tattoos, performerDetails.AddedTattoos) s.compareBodyModifications(input.Piercings, performerDetails.AddedPiercings) assert.Equal(s.t, input.ImageIds, performerDetails.AddedImages) } func (s *performerEditTestRunner) verifyPerformerEdit(input models.PerformerEditDetailsInput, performer *models.Performer) { resolver := s.resolver.Performer() assert.True(s.t, input.Name == nil || (*input.Name == performer.Name)) if input.Disambiguation == nil { assert.Nil(s.t, performer.Disambiguation) } else { assert.Equal(s.t, *input.Disambiguation, *performer.Disambiguation) } aliases, _ := resolver.Aliases(s.ctx, performer) if len(input.Aliases) == 0 { assert.True(s.t, len(aliases) == 0) } else { assert.Equal(s.t, input.Aliases, aliases) } if input.Gender == nil { assert.Nil(s.t, performer.Gender) } else { assert.Equal(s.t, input.Gender.String(), performer.Gender.String()) } urls, _ := resolver.Urls(s.ctx, performer) assert.Equal(s.t, input.Urls, urls) if input.Birthdate == nil { assert.Nil(s.t, performer.BirthDate) } else { assert.Equal(s.t, *input.Birthdate, *performer.BirthDate) } if input.Deathdate == nil { assert.Nil(s.t, performer.DeathDate) } else { assert.Equal(s.t, *input.Deathdate, *performer.DeathDate) } if input.Ethnicity == nil { assert.Nil(s.t, performer.Ethnicity) } else { assert.Equal(s.t, input.Ethnicity.String(), performer.Ethnicity.String()) } if input.Country == nil { assert.Nil(s.t, performer.Country) } else { assert.Equal(s.t, *input.Country, *performer.Country) } if input.EyeColor == nil { assert.Nil(s.t, performer.EyeColor) } else { assert.Equal(s.t, input.EyeColor.String(), performer.EyeColor.String()) } if input.HairColor == nil { assert.Nil(s.t, performer.HairColor) } else { assert.Equal(s.t, input.HairColor.String(), performer.HairColor.String()) } if input.Height == nil { assert.Nil(s.t, performer.Height) } else { assert.Equal(s.t, *input.Height, *performer.Height) } if input.BandSize == nil { assert.Nil(s.t, performer.BandSize) } else { assert.Equal(s.t, *input.BandSize, *performer.BandSize) } if input.CupSize == nil { assert.Nil(s.t, performer.CupSize) } else { assert.Equal(s.t, *input.CupSize, *performer.CupSize) } if input.WaistSize == nil { assert.Nil(s.t, performer.WaistSize) } else { assert.Equal(s.t, *input.WaistSize, *performer.WaistSize) } if input.HipSize == nil { assert.Nil(s.t, performer.HipSize) } else { assert.Equal(s.t, *input.HipSize, *performer.HipSize) } if input.BreastType == nil { assert.Nil(s.t, performer.BreastType) } else { assert.Equal(s.t, input.BreastType.String(), performer.BreastType.String()) } if input.CareerStartYear == nil { assert.Nil(s.t, performer.CareerStartYear) } else { assert.Equal(s.t, *input.CareerStartYear, *performer.CareerStartYear) } if input.CareerEndYear == nil { assert.Nil(s.t, performer.CareerEndYear) } else { assert.Equal(s.t, *input.CareerEndYear, *performer.CareerEndYear) } tattoos, _ := resolver.Tattoos(s.ctx, performer) if len(input.Tattoos) == 0 { assert.True(s.t, len(tattoos) == 0) } else { s.compareBodyModifications(input.Tattoos, tattoos) } piercings, _ := resolver.Piercings(s.ctx, performer) if len(input.Piercings) == 0 { assert.True(s.t, len(piercings) == 0) } else { s.compareBodyModifications(input.Piercings, piercings) } images, _ := resolver.Images(s.ctx, performer) var imageIds []uuid.UUID for _, image := range images { imageIds = append(imageIds, image.ID) } assert.Equal(s.t, input.ImageIds, imageIds) } func (s *performerEditTestRunner) testDestroyPerformerEdit() { createdPerformer, err := s.createTestPerformer(nil) assert.NoError(s.t, err) performerID := createdPerformer.UUID() performerEditDetailsInput := models.PerformerEditDetailsInput{} editInput := models.EditInput{ Operation: models.OperationEnumDestroy, ID: &performerID, } destroyEdit, err := s.createTestPerformerEdit(models.OperationEnumDestroy, &performerEditDetailsInput, &editInput, nil) assert.NoError(s.t, err) s.verifyDestroyPerformerEdit(performerID, destroyEdit) } func (s *performerEditTestRunner) verifyDestroyPerformerEdit(performerID uuid.UUID, edit *models.Edit) { s.verifyEditOperation(models.OperationEnumDestroy.String(), edit) s.verifyEditStatus(models.VoteStatusEnumPending.String(), edit) s.verifyEditTargetType(models.TargetTypeEnumPerformer.String(), edit) s.verifyEditApplication(false, edit) editTarget := s.getEditPerformerTarget(edit) assert.Equal(s.t, performerID, editTarget.ID) } func (s *performerEditTestRunner) testMergePerformerEdit() { existingName := "performerName2" existingAlias := "performerAlias2" performerCreateInput := models.PerformerCreateInput{ Name: existingName, Aliases: []string{existingAlias}, } createdPrimaryPerformer, err := s.createTestPerformer(&performerCreateInput) assert.NoError(s.t, err) createdMergePerformer, err := s.createTestPerformer(nil) assert.NoError(s.t, err) performerEditDetailsInput := s.createPerformerEditDetailsInput() id := createdPrimaryPerformer.UUID() mergeSources := []uuid.UUID{createdMergePerformer.UUID()} editInput := models.EditInput{ Operation: models.OperationEnumMerge, ID: &id, MergeSourceIds: mergeSources, } createdMergeEdit, err := s.createTestPerformerEdit(models.OperationEnumMerge, performerEditDetailsInput, &editInput, nil) assert.NoError(s.t, err) s.verifyMergePerformerEdit(createdPrimaryPerformer, *performerEditDetailsInput, createdMergeEdit, mergeSources) } func (s *performerEditTestRunner) verifyMergePerformerEdit(originalPerformer *performerOutput, input models.PerformerEditDetailsInput, edit *models.Edit, inputMergeSources []uuid.UUID) { s.verifyEditOperation(models.OperationEnumMerge.String(), edit) s.verifyEditStatus(models.VoteStatusEnumPending.String(), edit) s.verifyEditTargetType(models.TargetTypeEnumPerformer.String(), edit) s.verifyEditApplication(false, edit) s.verifyPerformerEditDetails(input, edit) var mergeSources []uuid.UUID merges, _ := s.resolver.Edit().MergeSources(s.ctx, edit) for i := range merges { merge := merges[i].(*models.Performer) mergeSources = append(mergeSources, merge.ID) } assert.Equal(s.t, inputMergeSources, mergeSources) } func (s *performerEditTestRunner) testApplyCreatePerformerEdit() { performerEditDetailsInput := s.createPerformerEditDetailsInput() edit, err := s.createTestPerformerEdit(models.OperationEnumCreate, performerEditDetailsInput, nil, nil) assert.NoError(s.t, err) appliedEdit, err := s.applyEdit(edit.ID) assert.NoError(s.t, err) s.verifyAppliedPerformerCreateEdit(*performerEditDetailsInput, appliedEdit) } func (s *performerEditTestRunner) verifyAppliedPerformerCreateEdit(input models.PerformerEditDetailsInput, edit *models.Edit) { assert.True(s.t, edit.ID != uuid.Nil, "Expected created edit id to be non-zero") s.verifyEditOperation(models.OperationEnumCreate.String(), edit) s.verifyEditStatus(models.VoteStatusEnumImmediateAccepted.String(), edit) s.verifyEditTargetType(models.TargetTypeEnumPerformer.String(), edit) s.verifyEditApplication(true, edit) performer := s.getEditPerformerTarget(edit) s.verifyPerformerEdit(input, performer) } func (s *performerEditTestRunner) testApplyModifyPerformerEdit() { site, err := s.createTestSite(nil) assert.NoError(s.t, err) performerCreateInput := models.PerformerCreateInput{ Name: "performerName3", Aliases: []string{"modfied performer alias"}, Tattoos: []models.BodyModificationInput{ { Location: "some tattoo location", }, }, Piercings: []models.BodyModificationInput{ { Location: "some piercing location", }, }, Urls: []models.URL{ { URL: "http://example.org/asd", SiteID: site.ID, }, }, } createdPerformer, err := s.createTestPerformer(&performerCreateInput) assert.NoError(s.t, err) // Create edit that replaces all metadata for the performer performerEditDetailsInput := s.createPerformerEditDetailsInput() id := createdPerformer.UUID() editInput := models.EditInput{ Operation: models.OperationEnumModify, ID: &id, } createdUpdateEdit, err := s.createTestPerformerEdit(models.OperationEnumModify, performerEditDetailsInput, &editInput, nil) assert.NoError(s.t, err) appliedEdit, err := s.applyEdit(createdUpdateEdit.ID) assert.NoError(s.t, err) modifiedPerformer, _ := s.resolver.Query().FindPerformer(s.ctx, id) s.verifyAppliedPerformerEdit(appliedEdit) s.verifyPerformerEdit(*performerEditDetailsInput, modifiedPerformer) } func (s *performerEditTestRunner) testApplyModifyPerformerWithoutAliases() { createdPerformer, err := s.createTestPerformer(nil) assert.NoError(s.t, err) sceneAppearance := models.PerformerAppearanceInput{ PerformerID: createdPerformer.UUID(), } sceneInput := models.SceneCreateInput{ Performers: []models.PerformerAppearanceInput{ sceneAppearance, }, Date: "2020-01-02", } scene, err := s.createTestScene(&sceneInput) assert.NoError(s.t, err) performerEditDetailsInput := s.createPerformerEditDetailsInput() id := createdPerformer.UUID() editInput := models.EditInput{ Operation: models.OperationEnumModify, ID: &id, } createdUpdateEdit, err := s.createTestPerformerEdit(models.OperationEnumModify, performerEditDetailsInput, &editInput, nil) assert.NoError(s.t, err) _, err = s.applyEdit(createdUpdateEdit.ID) assert.NoError(s.t, err) scene, err = s.client.findScene(scene.UUID()) assert.NoError(s.t, err, "Error finding scene") s.verifyPerformanceAlias(scene, nil) performer, err := s.client.findPerformer(id) assert.NoError(s.t, err, "Error finding performer") performerEditDetailsInput = s.createPerformerEditDetailsInput() editInput = models.EditInput{ Operation: models.OperationEnumModify, ID: &id, } aliasVal := true options := models.PerformerEditOptionsInput{ SetModifyAliases: &aliasVal, } createdUpdateEdit, err = s.createTestPerformerEdit(models.OperationEnumModify, performerEditDetailsInput, &editInput, &options) assert.NoError(s.t, err) _, err = s.applyEdit(createdUpdateEdit.ID) assert.NoError(s.t, err) scene, err = s.client.findScene(scene.UUID()) assert.NoError(s.t, err, "Error finding scene") // set modify aliases was set to true - this should be set to the old name s.verifyPerformanceAlias(scene, &performer.Name) } func (s *performerEditTestRunner) testApplyModifyPerformerWithAliases() { createdPerformer, err := s.createTestPerformer(nil) assert.NoError(s.t, err) sceneAppearance := models.PerformerAppearanceInput{ PerformerID: createdPerformer.UUID(), } sceneInput := models.SceneCreateInput{ Performers: []models.PerformerAppearanceInput{ sceneAppearance, }, Date: "2020-01-02", } scene, err := s.createTestScene(&sceneInput) assert.NoError(s.t, err) performerEditDetailsInput := s.createPerformerEditDetailsInput() id := createdPerformer.UUID() editInput := models.EditInput{ Operation: models.OperationEnumModify, ID: &id, } aliasVal := true options := models.PerformerEditOptionsInput{ SetModifyAliases: &aliasVal, } createdUpdateEdit, err := s.createTestPerformerEdit(models.OperationEnumModify, performerEditDetailsInput, &editInput, &options) assert.NoError(s.t, err) _, err = s.applyEdit(createdUpdateEdit.ID) assert.NoError(s.t, err) scene, err = s.client.findScene(scene.UUID()) assert.NoError(s.t, err, "Error finding scene") s.verifyPerformanceAlias(scene, &createdPerformer.Name) } func (s *performerEditTestRunner) testApplyModifyUnsetPerformerEdit() { performerData := s.createFullPerformerCreateInput() createdPerformer, err := s.createTestPerformer(performerData) assert.NoError(s.t, err) id := createdPerformer.UUID() var resp struct { PerformerEdit struct { ID string } } s.client.MustPost(fmt.Sprintf(` mutation { performerEdit(input: { edit: {id: "%v", operation: MODIFY} details: { aliases: [], tattoos: [], piercings: [], urls: [], disambiguation: null } }) { id } } `, id), &resp) edit, _ := s.applyEdit(uuid.FromStringOrNil(resp.PerformerEdit.ID)) s.verifyAppliedPerformerEdit(edit) var performer struct { FindPerformer struct { Height int ID string Disambiguation string Aliases []string URLs []models.URL Piercings []models.BodyModification Tattoos []models.BodyModification } } s.client.MustPost(fmt.Sprintf(` query { findPerformer(id: "%v") { disambiguation height aliases urls { url } piercings { location } tattoos { location } } } `, id), &performer) assert.Equal(s.t, performer.FindPerformer.Disambiguation, "") assert.Equal(s.t, performer.FindPerformer.Height, *performerData.Height) assert.True(s.t, len(performer.FindPerformer.Aliases) == 0) assert.True(s.t, len(performer.FindPerformer.URLs) == 0) assert.True(s.t, len(performer.FindPerformer.Piercings) == 0) assert.True(s.t, len(performer.FindPerformer.Tattoos) == 0) } func (s *performerEditTestRunner) testApplyDestroyPerformerEdit() { createdPerformer, err := s.createTestPerformer(nil) assert.NoError(s.t, err) performerID := createdPerformer.UUID() appearance := models.PerformerAppearanceInput{ PerformerID: performerID, } sceneInput := models.SceneCreateInput{ Performers: []models.PerformerAppearanceInput{appearance}, Date: "2020-03-02", } scene, _ := s.createTestScene(&sceneInput) performerEditDetailsInput := models.PerformerEditDetailsInput{} editInput := models.EditInput{ Operation: models.OperationEnumDestroy, ID: &performerID, } destroyEdit, err := s.createTestPerformerEdit(models.OperationEnumDestroy, &performerEditDetailsInput, &editInput, nil) assert.NoError(s.t, err) appliedEdit, err := s.applyEdit(destroyEdit.ID) assert.NoError(s.t, err) destroyedPerformer, err := s.resolver.Query().FindPerformer(s.ctx, performerID) assert.NoError(s.t, err) scene, err = s.client.findScene(scene.UUID()) assert.NoError(s.t, err, "Error finding scene") s.verifyApplyDestroyPerformerEdit(destroyedPerformer, appliedEdit, scene) } func (s *performerEditTestRunner) verifyApplyDestroyPerformerEdit(destroyedPerformer *models.Performer, edit *models.Edit, scene *sceneOutput) { s.verifyEditOperation(models.OperationEnumDestroy.String(), edit) s.verifyEditStatus(models.VoteStatusEnumImmediateAccepted.String(), edit) s.verifyEditTargetType(models.TargetTypeEnumPerformer.String(), edit) s.verifyEditApplication(true, edit) assert.True(s.t, destroyedPerformer.Deleted, true) scenePerformers := scene.Performers assert.True(s.t, len(scenePerformers) == 0) } func (s *performerEditTestRunner) testApplyMergePerformerEdit() { mergeSource1, err := s.createTestPerformer(nil) assert.NoError(s.t, err) mergeSource2, err := s.createTestPerformer(nil) assert.NoError(s.t, err) mergeTarget, err := s.createTestPerformer(nil) assert.NoError(s.t, err) mergeSource1Appearance := models.PerformerAppearanceInput{ PerformerID: mergeSource1.UUID(), } mergeSource2Appearance := models.PerformerAppearanceInput{ PerformerID: mergeSource2.UUID(), } mergeTargetAppearance := models.PerformerAppearanceInput{ PerformerID: mergeTarget.UUID(), } // Scene with performer from both source and target, should not cause db unique error sceneInput := models.SceneCreateInput{ Performers: []models.PerformerAppearanceInput{ mergeSource2Appearance, mergeTargetAppearance, }, Date: "2020-02-03", } scene1, err := s.createTestScene(&sceneInput) assert.NoError(s.t, err) sceneInput = models.SceneCreateInput{ Performers: []models.PerformerAppearanceInput{ mergeSource1Appearance, mergeSource2Appearance, }, Date: "2020-03-02", } scene2, err := s.createTestScene(&sceneInput) assert.NoError(s.t, err) performerEditDetailsInput := s.createPerformerEditDetailsInput() mergeSources := []uuid.UUID{ mergeSource1.UUID(), mergeSource2.UUID(), } setMergeAliases := true options := models.PerformerEditOptionsInput{ SetMergeAliases: &setMergeAliases, } id := mergeTarget.UUID() editInput := models.EditInput{ Operation: models.OperationEnumMerge, ID: &id, MergeSourceIds: mergeSources, } mergeEdit, err := s.createTestPerformerEdit(models.OperationEnumMerge, performerEditDetailsInput, &editInput, &options) assert.NoError(s.t, err) appliedMerge, err := s.applyEdit(mergeEdit.ID) assert.NoError(s.t, err) scene1, err = s.client.findScene(scene1.UUID()) assert.NoError(s.t, err, "Error finding scene") scene2, err = s.client.findScene(scene2.UUID()) assert.NoError(s.t, err, "Error finding scene") s.verifyAppliedMergePerformerEdit(*performerEditDetailsInput, appliedMerge, scene1, scene2) // Target already attached, so should not get alias s.verifyPerformanceAlias(scene1, nil) s.verifyPerformanceAlias(scene2, &mergeSource1.Name) // Verify merged_ids and merged_into_id fields targetPerformer, err := s.resolver.Query().FindPerformer(s.ctx, mergeTarget.UUID()) assert.NoError(s.t, err) mergedIds, err := s.resolver.Performer().MergedIds(s.ctx, targetPerformer) assert.NoError(s.t, err) assert.Equal(s.t, 2, len(mergedIds), "Target should have 2 performers merged into it") assert.True(s.t, contains(mergedIds, mergeSource1.UUID()), "Target should contain source1 in merged_ids") assert.True(s.t, contains(mergedIds, mergeSource2.UUID()), "Target should contain source2 in merged_ids") mergedIntoID, err := s.resolver.Performer().MergedIntoID(s.ctx, targetPerformer) assert.NoError(s.t, err) assert.Nil(s.t, mergedIntoID, "Target performer should not be merged into anything") source1Performer, err := s.resolver.Query().FindPerformer(s.ctx, mergeSource1.UUID()) assert.NoError(s.t, err) source1MergedIds, err := s.resolver.Performer().MergedIds(s.ctx, source1Performer) assert.NoError(s.t, err) assert.Equal(s.t, 0, len(source1MergedIds), "Source performer should have no performers merged into it") source1MergedIntoID, err := s.resolver.Performer().MergedIntoID(s.ctx, source1Performer) assert.NoError(s.t, err) assert.NotNil(s.t, source1MergedIntoID, "Source performer should be merged into target") assert.Equal(s.t, mergeTarget.UUID(), *source1MergedIntoID, "Source should be merged into target") } func (s *performerEditTestRunner) verifyAppliedMergePerformerEdit(input models.PerformerEditDetailsInput, edit *models.Edit, scene1 *sceneOutput, scene2 *sceneOutput) { s.verifyEditOperation(models.OperationEnumMerge.String(), edit) s.verifyEditStatus(models.VoteStatusEnumImmediateAccepted.String(), edit) s.verifyEditTargetType(models.TargetTypeEnumPerformer.String(), edit) s.verifyEditApplication(true, edit) s.verifyPerformerEditDetails(input, edit) merges, _ := s.resolver.Edit().MergeSources(s.ctx, edit) for i := range merges { performer := merges[i].(*models.Performer) assert.True(s.t, performer.Deleted == true) } editTarget := s.getEditPerformerTarget(edit) scene1Performers := scene1.Performers assert.True(s.t, len(scene1Performers) == 1) assert.Equal(s.t, scene1Performers[0].Performer.ID, editTarget.ID.String()) scene2Performers := scene2.Performers assert.True(s.t, len(scene2Performers) == 1) assert.Equal(s.t, scene2Performers[0].Performer.ID, editTarget.ID.String()) } func (s *performerEditTestRunner) verifyPerformanceAlias(scene *sceneOutput, alias *string) { scenePerformers := scene.Performers assert.True(s.t, len(scenePerformers) == 1) if alias == nil { assert.True(s.t, len(scenePerformers) == 0 || scenePerformers[0].As == nil) } else { assert.NotNil(s.t, scenePerformers[0].As) assert.True(s.t, *alias == *scenePerformers[0].As) } } func (s *performerEditTestRunner) testApplyMergePerformerEditWithoutAlias() { mergeSource, err := s.createTestPerformer(nil) assert.NoError(s.t, err) mergeTarget, err := s.createTestPerformer(nil) assert.NoError(s.t, err) mergeSourceAppearance := models.PerformerAppearanceInput{ PerformerID: mergeSource.UUID(), } sceneInput := models.SceneCreateInput{ Performers: []models.PerformerAppearanceInput{ mergeSourceAppearance, }, Date: "2020-03-02", } scene, err := s.createTestScene(&sceneInput) assert.NoError(s.t, err) performerEditDetailsInput := s.createPerformerEditDetailsInput() id := mergeTarget.UUID() mergeSources := []uuid.UUID{mergeSource.UUID()} editInput := models.EditInput{ Operation: models.OperationEnumMerge, ID: &id, MergeSourceIds: mergeSources, } mergeEdit, err := s.createTestPerformerEdit(models.OperationEnumMerge, performerEditDetailsInput, &editInput, nil) assert.NoError(s.t, err) _, err = s.applyEdit(mergeEdit.ID) assert.NoError(s.t, err) scene, err = s.client.findScene(scene.UUID()) assert.NoError(s.t, err, "Error finding scene") s.verifyPerformanceAlias(scene, nil) } func (s *performerTestRunner) testChangeURLSite() { site, err := s.createTestSite(nil) assert.NoError(s.t, err) input := &models.PerformerCreateInput{ Name: s.generatePerformerName(), Urls: []models.URL{ { URL: "URL", SiteID: site.ID, }, }, } createdPerformer, err := s.createTestPerformer(input) siteTwo, err := s.createTestSite(nil) assert.NoError(s.t, err) updateInput := &models.PerformerEditDetailsInput{ Urls: []models.URL{ { URL: "URL", SiteID: siteTwo.ID, }, }, } id := uuid.FromStringOrNil(createdPerformer.ID) editInput := models.EditInput{ Operation: models.OperationEnumModify, ID: &id, } modifyEdit, err := s.createTestPerformerEdit(models.OperationEnumModify, updateInput, &editInput, nil) assert.NoError(s.t, err) _, err = s.applyEdit(modifyEdit.ID) assert.NoError(s.t, err) performer, _ := s.resolver.Query().FindPerformer(s.ctx, id) urls, _ := s.resolver.Performer().Urls(s.ctx, performer) assert.Equal(s.t, updateInput.Urls, urls) } func (s *performerEditTestRunner) testPerformerEditUpdate() { // Create a pending edit with initial details performerEditDetailsInput := s.createPerformerEditDetailsInput() createdEdit, err := s.createTestPerformerEdit(models.OperationEnumCreate, performerEditDetailsInput, nil, nil) assert.NoError(s.t, err) // Verify initial state assert.Equal(s.t, 0, createdEdit.UpdateCount, "Initial update_count should be 0") assert.Nil(s.t, createdEdit.UpdatedAt, "Initial updated timestamp should be nil") // Update the edit with new details newName := "Updated Performer Name" newGender := models.GenderEnumMale newBirthdate := "1995-06-15" newHeight := 175 updatedDetails := models.PerformerEditDetailsInput{ Name: &newName, Gender: &newGender, Birthdate: &newBirthdate, Height: &newHeight, } editID := createdEdit.ID updatedEdit, err := s.resolver.Mutation().PerformerEditUpdate(s.ctx, createdEdit.ID, models.PerformerEditInput{ Edit: &models.EditInput{Operation: models.OperationEnumCreate}, Details: &updatedDetails, }) assert.NoError(s.t, err, "Error updating performer edit") // Verify basic properties assert.Equal(s.t, createdEdit.ID, updatedEdit.ID, "Edit ID should not change") assert.NotNil(s.t, updatedEdit, "Updated edit should not be nil") // Verify update_count was incremented assert.Equal(s.t, 1, updatedEdit.UpdateCount, "update_count should be incremented to 1") // Verify updated timestamp is set assert.NotNil(s.t, updatedEdit.UpdatedAt, "updated timestamp should be set after update") // Verify edit is still pending (not applied) s.verifyEditStatus(models.VoteStatusEnumPending.String(), updatedEdit) s.verifyEditApplication(false, updatedEdit) // Verify the new details are persisted s.verifyPerformerEditDetails(updatedDetails, updatedEdit) // Re-fetch the edit from the database to ensure persistence refetchedEdit, err := s.resolver.Query().FindEdit(s.ctx, createdEdit.ID) assert.NoError(s.t, err, "Error re-fetching edit") assert.Equal(s.t, 1, refetchedEdit.UpdateCount, "update_count should persist in database") s.verifyPerformerEditDetails(updatedDetails, refetchedEdit) // Attempt to update the edit again - should fail due to update limit secondUpdateName := "Second Update Name" secondUpdatedDetails := models.PerformerEditDetailsInput{ Name: &secondUpdateName, Gender: &newGender, Birthdate: &newBirthdate, Height: &newHeight, } _, err = s.resolver.Mutation().PerformerEditUpdate(s.ctx, createdEdit.ID, models.PerformerEditInput{ Edit: &models.EditInput{ID: &editID, Operation: models.OperationEnumCreate}, Details: &secondUpdatedDetails, }) // Verify that the update limit error is returned assert.ErrorContains(s.t, err, "edit update limit reached") } func TestCreatePerformerEdit(t *testing.T) { pt := createPerformerEditTestRunner(t) pt.testCreatePerformerEdit() } func TestModifyPerformerEdit(t *testing.T) { pt := createPerformerEditTestRunner(t) pt.testModifyPerformerEdit() } func TestDestroyPerformerEdit(t *testing.T) { pt := createPerformerEditTestRunner(t) pt.testDestroyPerformerEdit() } func TestMergePerformerEdit(t *testing.T) { pt := createPerformerEditTestRunner(t) pt.testMergePerformerEdit() } func TestApplyCreatePerformerEdit(t *testing.T) { pt := createPerformerEditTestRunner(t) pt.testApplyCreatePerformerEdit() } func TestApplyModifyPerformerEdit(t *testing.T) { pt := createPerformerEditTestRunner(t) pt.testApplyModifyPerformerEdit() } func TestApplyModifyPerformerEditOptions(t *testing.T) { pt := createPerformerEditTestRunner(t) pt.testApplyModifyPerformerWithAliases() pt.testApplyModifyPerformerWithoutAliases() } func TestApplyMergePerformerEditWithoutAlias(t *testing.T) { pt := createPerformerEditTestRunner(t) pt.testApplyMergePerformerEditWithoutAlias() } func TestApplyModifyUnsetPerformerEdit(t *testing.T) { pt := createPerformerEditTestRunner(t) pt.testApplyModifyUnsetPerformerEdit() } func TestApplyDestroyPerformerEdit(t *testing.T) { pt := createPerformerEditTestRunner(t) pt.testApplyDestroyPerformerEdit() } func TestApplyMergePerformerEdit(t *testing.T) { pt := createPerformerEditTestRunner(t) pt.testApplyMergePerformerEdit() } func TestChangeURLSite(t *testing.T) { pt := createPerformerTestRunner(t) pt.testChangeURLSite() } func TestPerformerEditUpdate(t *testing.T) { pt := createPerformerEditTestRunner(t) pt.testPerformerEditUpdate() } func (s *performerEditTestRunner) testQueryExistingPerformer() { // Create a performer edit for testing site, err := s.createTestSite(nil) assert.NoError(s.t, err) performerName := "Test Performer Name" performerDisambiguation := "Test Disambiguation" testURL := "http://example.com/performer123" performerEditDetailsInput := models.PerformerEditDetailsInput{ Name: &performerName, Disambiguation: &performerDisambiguation, Urls: []models.URL{ { URL: testURL, SiteID: site.ID, }, }, } edit, err := s.createTestPerformerEdit(models.OperationEnumCreate, &performerEditDetailsInput, nil, nil) assert.NoError(s.t, err) // Test 1: Query by URL - should find the edit var resp1 struct { QueryExistingPerformer struct { Edits []struct { ID string } } } s.client.MustPost(fmt.Sprintf(` query { queryExistingPerformer(input: { urls: ["%v"] }) { edits { id } } } `, testURL), &resp1) assert.True(s.t, len(resp1.QueryExistingPerformer.Edits) > 0, "Should find edit by URL") // Test 2: Query by name and disambiguation - should find the edit var resp2 struct { QueryExistingPerformer struct { Edits []struct { ID string } } } s.client.MustPost(fmt.Sprintf(` query { queryExistingPerformer(input: { name: "%v" disambiguation: "%v" urls: [] }) { edits { id } } } `, performerName, performerDisambiguation), &resp2) assert.True(s.t, len(resp2.QueryExistingPerformer.Edits) > 0, "Should find edit by name and disambiguation") // Test 3: Cancel the edit and verify it no longer appears _, err = s.resolver.Mutation().CancelEdit(s.ctx, models.CancelEditInput{ ID: edit.ID, }) assert.NoError(s.t, err) var resp3 struct { QueryExistingPerformer struct { Edits []struct { ID string } } } s.client.MustPost(fmt.Sprintf(` query { queryExistingPerformer(input: { urls: ["%v"] }) { edits { id } } } `, testURL), &resp3) assert.True(s.t, len(resp3.QueryExistingPerformer.Edits) == 0, "Should not find cancelled edit") // Test 4: Create an actual performer (without disambiguation) and verify it appears in results performerName2 := "Test Performer Name 2" testURL2 := "http://example.com/performer456" actualPerformerInput := models.PerformerCreateInput{ Name: performerName2, Urls: []models.URL{ { URL: testURL2, SiteID: site.ID, }, }, } createdPerformer, err := s.createTestPerformer(&actualPerformerInput) assert.NoError(s.t, err) // Query by name only (works because performer has no disambiguation) var resp4 struct { QueryExistingPerformer struct { Performers []struct { ID string } } } s.client.MustPost(fmt.Sprintf(` query { queryExistingPerformer(input: { name: "%v" urls: [] }) { performers { id } } } `, performerName2), &resp4) assert.True(s.t, len(resp4.QueryExistingPerformer.Performers) > 0, "Should find created performer by name") assert.Equal(s.t, createdPerformer.ID, resp4.QueryExistingPerformer.Performers[0].ID, "Should return the correct performer") // Test 5: Query by URL for the created performer var resp5 struct { QueryExistingPerformer struct { Performers []struct { ID string } } } s.client.MustPost(fmt.Sprintf(` query { queryExistingPerformer(input: { urls: ["%v"] }) { performers { id } } } `, testURL2), &resp5) assert.True(s.t, len(resp5.QueryExistingPerformer.Performers) > 0, "Should find created performer by URL") assert.Equal(s.t, createdPerformer.ID, resp5.QueryExistingPerformer.Performers[0].ID, "Should return the correct performer by URL") // Test 6: Create a performer WITH disambiguation and query with matching disambiguation performerName3 := "Test Performer Name 3" performerDisambiguation3 := "Test Disambiguation 3" testURL3 := "http://example.com/performer789" actualPerformerInput3 := models.PerformerCreateInput{ Name: performerName3, Disambiguation: &performerDisambiguation3, Urls: []models.URL{ { URL: testURL3, SiteID: site.ID, }, }, } createdPerformer3, err := s.createTestPerformer(&actualPerformerInput3) assert.NoError(s.t, err) var resp6 struct { QueryExistingPerformer struct { Performers []struct { ID string } } } s.client.MustPost(fmt.Sprintf(` query { queryExistingPerformer(input: { name: "%v" disambiguation: "%v" urls: [] }) { performers { id } } } `, performerName3, performerDisambiguation3), &resp6) assert.True(s.t, len(resp6.QueryExistingPerformer.Performers) > 0, "Should find created performer by name and disambiguation") assert.Equal(s.t, createdPerformer3.ID, resp6.QueryExistingPerformer.Performers[0].ID, "Should return the correct performer with disambiguation") } func TestQueryExistingPerformer(t *testing.T) { pt := createPerformerEditTestRunner(t) pt.testQueryExistingPerformer() } func (s *performerEditTestRunner) testApplyModifyPerformerEnumFields() { initialGender := models.GenderEnumMale initialEthnicity := models.EthnicityEnumAsian initialHairColor := models.HairColorEnumBlonde initialEyeColor := models.EyeColorEnumBlue initialBreastType := models.BreastTypeEnumNatural performerCreateInput := models.PerformerCreateInput{ Name: "Enum Test Performer", Gender: &initialGender, Ethnicity: &initialEthnicity, HairColor: &initialHairColor, EyeColor: &initialEyeColor, BreastType: &initialBreastType, } createdPerformer, err := s.createTestPerformer(&performerCreateInput) assert.NoError(s.t, err) newGender := models.GenderEnumFemale newEthnicity := models.EthnicityEnumCaucasian newHairColor := models.HairColorEnumBrunette newEyeColor := models.EyeColorEnumGreen newBreastType := models.BreastTypeEnumFake performerEditDetailsInput := models.PerformerEditDetailsInput{ Gender: &newGender, Ethnicity: &newEthnicity, HairColor: &newHairColor, EyeColor: &newEyeColor, BreastType: &newBreastType, } id := createdPerformer.UUID() editInput := models.EditInput{ Operation: models.OperationEnumModify, ID: &id, } createdUpdateEdit, err := s.createTestPerformerEdit(models.OperationEnumModify, &performerEditDetailsInput, &editInput, nil) assert.NoError(s.t, err) appliedEdit, err := s.applyEdit(createdUpdateEdit.ID) assert.NoError(s.t, err) s.verifyAppliedPerformerEdit(appliedEdit) modifiedPerformer, err := s.resolver.Query().FindPerformer(s.ctx, id) assert.NoError(s.t, err) assert.Equal(s.t, newGender.String(), modifiedPerformer.Gender.String()) assert.Equal(s.t, newEthnicity.String(), modifiedPerformer.Ethnicity.String()) assert.Equal(s.t, newHairColor.String(), modifiedPerformer.HairColor.String()) assert.Equal(s.t, newEyeColor.String(), modifiedPerformer.EyeColor.String()) assert.Equal(s.t, newBreastType.String(), modifiedPerformer.BreastType.String()) } func TestApplyModifyPerformerEnumFields(t *testing.T) { pt := createPerformerEditTestRunner(t) pt.testApplyModifyPerformerEnumFields() } ================================================ FILE: internal/api/performer_integration_test.go ================================================ //go:build integration package api_test import ( "testing" "time" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" "github.com/stretchr/testify/assert" ) type performerTestRunner struct { testRunner } func createPerformerTestRunner(t *testing.T) *performerTestRunner { return &performerTestRunner{ testRunner: *asAdmin(t), } } func (s *performerTestRunner) testCreatePerformer() { disambiguation := "Disambiguation" country := "USA" height := 182 cupSize := "C" bandSize := 32 careerStartYear := 2000 tattooDesc := "Foobar" gender := models.GenderEnumFemale ethnicity := models.EthnicityEnumCaucasian eyeColor := models.EyeColorEnumBlue hairColor := models.HairColorEnumBlonde breastType := models.BreastTypeEnumNatural birthdate := "2001-02-03" deathdate := "2024-12-23" site, err := s.createTestSite(nil) assert.NoError(s.t, err) input := models.PerformerCreateInput{ Name: s.generatePerformerName(), Disambiguation: &disambiguation, Aliases: []string{"Alias1", "Alias2"}, Gender: &gender, Urls: []models.URL{ { URL: "URL", SiteID: site.ID, }, }, Birthdate: &birthdate, Deathdate: &deathdate, Ethnicity: ðnicity, Country: &country, EyeColor: &eyeColor, HairColor: &hairColor, Height: &height, CupSize: &cupSize, BandSize: &bandSize, WaistSize: &bandSize, HipSize: &bandSize, BreastType: &breastType, CareerStartYear: &careerStartYear, CareerEndYear: nil, Tattoos: []models.BodyModificationInput{ { Location: "Inner thigh", Description: &tattooDesc, }, }, Piercings: []models.BodyModificationInput{ { Location: "Nose", Description: nil, }, }, } performer, err := s.resolver.Mutation().PerformerCreate(s.ctx, input) assert.NoError(s.t, err) s.verifyCreatedPerformer(input, performer) } func (s *performerTestRunner) verifyCreatedPerformer(input models.PerformerCreateInput, performer *models.Performer) { // ensure basic attributes are set correctly assert.Equal(s.t, input.Name, performer.Name) r := s.resolver.Performer() assert.True(s.t, performer.ID != uuid.Nil, "Expected created performer id to be non-zero") assert.Equal(s.t, performer.Disambiguation, input.Disambiguation) alias, _ := r.Aliases(s.ctx, performer) assert.Equal(s.t, alias, input.Aliases) assert.Equal(s.t, performer.Gender, input.Gender) urls, _ := s.resolver.Performer().Urls(s.ctx, performer) assert.Equal(s.t, input.Urls, urls) birthdate, _ := r.Birthdate(s.ctx, performer) if input.Birthdate == nil { assert.Nil(s.t, birthdate) } else { assert.Equal(s.t, *input.Birthdate, birthdate.Date) } assert.Equal(s.t, performer.DeathDate, input.Deathdate) assert.Equal(s.t, performer.Ethnicity, input.Ethnicity) assert.Equal(s.t, performer.Country, input.Country) assert.Equal(s.t, performer.EyeColor, input.EyeColor) assert.Equal(s.t, performer.HairColor, input.HairColor) assert.Equal(s.t, performer.Height, input.Height) assert.Equal(s.t, performer.CupSize, input.CupSize) assert.Equal(s.t, performer.BandSize, input.BandSize) assert.Equal(s.t, performer.WaistSize, input.WaistSize) assert.Equal(s.t, performer.HipSize, input.HipSize) assert.Equal(s.t, performer.BreastType, input.BreastType) assert.Equal(s.t, performer.CareerStartYear, input.CareerStartYear) assert.Equal(s.t, performer.CareerEndYear, input.CareerEndYear) tattoos, _ := s.resolver.Performer().Tattoos(s.ctx, performer) assertBodyMods(s.t, input.Tattoos, tattoos, "Tattoos should match") piercings, _ := s.resolver.Performer().Piercings(s.ctx, performer) assertBodyMods(s.t, input.Piercings, piercings, "Piercings should match") } func (s *performerTestRunner) testFindPerformer() { createdPerformer, err := s.createTestPerformer(nil) assert.NoError(s.t, err) performer, err := s.resolver.Query().FindPerformer(s.ctx, createdPerformer.UUID()) assert.NoError(s.t, err, "Error finding performer") assert.NotNil(s.t, performer, "Did not find performer by id") // ensure values were set assert.Equal(s.t, createdPerformer.Name, performer.Name) } func (s *performerTestRunner) testUpdatePerformer() { cupSize := "C" bandSize := 32 tattooDesc := "Foobar" date := "2001-02-03" deathdate := "2024-11-23" site, err := s.createTestSite(nil) assert.NoError(s.t, err) input := &models.PerformerCreateInput{ Name: s.generatePerformerName(), Aliases: []string{"Alias1", "Alias2"}, Urls: []models.URL{ { URL: "URL", SiteID: site.ID, }, }, Birthdate: &date, Deathdate: &deathdate, CupSize: &cupSize, BandSize: &bandSize, WaistSize: &bandSize, HipSize: &bandSize, Tattoos: []models.BodyModificationInput{ { Location: "Inner thigh", Description: &tattooDesc, }, }, Piercings: []models.BodyModificationInput{ { Location: "Nose", Description: nil, }, }, } createdPerformer, err := s.createTestPerformer(input) assert.NoError(s.t, err) performerID := createdPerformer.UUID() updateInput := models.PerformerUpdateInput{ ID: performerID, Aliases: []string{"Alias3", "Alias4"}, Urls: []models.URL{ { URL: "URL", SiteID: site.ID, }, }, Birthdate: &date, Deathdate: &deathdate, CupSize: &cupSize, BandSize: &bandSize, WaistSize: &bandSize, HipSize: &bandSize, Tattoos: []models.BodyModificationInput{ { Location: "Tramp stamp", Description: &tattooDesc, }, }, Piercings: []models.BodyModificationInput{ { Location: "Navel", Description: nil, }, }, } // need some mocking of the context to make the field ignore behaviour work ctx := s.updateContext([]string{ "aliases", "urls", "birthdate", "deathdate", "tattoos", "piercings", "cup_size", "band_size", "waist_size", "hip_size", }) updatedPerformer, err := s.resolver.Mutation().PerformerUpdate(ctx, updateInput) assert.NoError(s.t, err) s.verifyUpdatedPerformer(updateInput, updatedPerformer) } func (s *performerTestRunner) verifyUpdatedPerformer(input models.PerformerUpdateInput, performer *models.Performer) { // ensure basic attributes are set correctly assert.True(s.t, input.Name == nil || *input.Name == performer.Name) r := s.resolver.Performer() aliases, _ := r.Aliases(s.ctx, performer) assert.Equal(s.t, aliases, input.Aliases) // ensure urls were set correctly urls, _ := s.resolver.Performer().Urls(s.ctx, performer) assert.Equal(s.t, input.Urls, urls) birthdate, _ := s.resolver.Performer().Birthdate(s.ctx, performer) if input.Birthdate == nil { assert.Nil(s.t, birthdate) } else { assert.Equal(s.t, *input.Birthdate, birthdate.Date) } assert.Equal(s.t, performer.DeathDate, input.Deathdate) tattoos, _ := s.resolver.Performer().Tattoos(s.ctx, performer) assertBodyMods(s.t, input.Tattoos, tattoos, "Tattoos should match") piercings, _ := s.resolver.Performer().Piercings(s.ctx, performer) assertBodyMods(s.t, input.Piercings, piercings, "Piercings should match") assert.Equal(s.t, performer.CupSize, input.CupSize) assert.Equal(s.t, performer.BandSize, input.BandSize) assert.Equal(s.t, performer.WaistSize, input.WaistSize) assert.Equal(s.t, performer.HipSize, input.HipSize) } func (s *performerTestRunner) testDestroyPerformer() { createdPerformer, err := s.createTestPerformer(nil) assert.NoError(s.t, err) performerID := createdPerformer.UUID() destroyed, err := s.resolver.Mutation().PerformerDestroy(s.ctx, models.PerformerDestroyInput{ ID: performerID, }) assert.NoError(s.t, err, "Error destroying performer") assert.True(s.t, destroyed, "Performer was not destroyed") // ensure cannot find performer foundPerformer, err := s.resolver.Query().FindPerformer(s.ctx, performerID) assert.NoError(s.t, err) assert.Nil(s.t, foundPerformer, "Found performer after destruction") // TODO - ensure scene was not removed } func (s *performerTestRunner) testQueryPerformers() { // Create test performers with specific attributes name1 := s.generatePerformerName() performer1, err := s.createTestPerformer(&models.PerformerCreateInput{ Name: name1, }) assert.NoError(s.t, err) name2 := s.generatePerformerName() performer2, err := s.createTestPerformer(&models.PerformerCreateInput{ Name: name2, }) assert.NoError(s.t, err) // Test basic query result, err := s.client.queryPerformers(models.PerformerQueryInput{ Page: 1, PerPage: 25, Direction: models.SortDirectionEnumAsc, Sort: models.PerformerSortEnumName, }) assert.NoError(s.t, err, "Error querying performers") // Ensure we have at least the performers we created assert.True(s.t, result.Count >= 2, "Expected at least 2 performers in count") assert.True(s.t, len(result.Performers) >= 2, "Expected at least 2 performers in results") // Verify our created performers are in the results found1 := false found2 := false for _, p := range result.Performers { if p.ID == performer1.ID { found1 = true assert.Equal(s.t, name1, p.Name) } if p.ID == performer2.ID { found2 = true assert.Equal(s.t, name2, p.Name) } } assert.True(s.t, found1, "Created performer 1 not found in query results") assert.True(s.t, found2, "Created performer 2 not found in query results") } func (s *performerTestRunner) testQueryPerformersBirthdate() { // Create test performers with specific birthdates birthdate1 := "2000-01-07" birthdate2 := "1995-06-15" birthdate3 := "2000-01-07" // Same as birthdate1 name1 := s.generatePerformerName() performer1, err := s.createTestPerformer(&models.PerformerCreateInput{ Name: name1, Birthdate: &birthdate1, }) assert.NoError(s.t, err) name2 := s.generatePerformerName() performer2, err := s.createTestPerformer(&models.PerformerCreateInput{ Name: name2, Birthdate: &birthdate2, }) assert.NoError(s.t, err) name3 := s.generatePerformerName() performer3, err := s.createTestPerformer(&models.PerformerCreateInput{ Name: name3, Birthdate: &birthdate3, }) assert.NoError(s.t, err) // Test EQUALS modifier equalsResult, err := s.client.queryPerformers(models.PerformerQueryInput{ Page: 1, PerPage: 100, Direction: models.SortDirectionEnumAsc, Sort: models.PerformerSortEnumName, Birthdate: &models.DateCriterionInput{ Value: birthdate1, Modifier: models.CriterionModifierEquals, }, }) assert.NoError(s.t, err, "Error querying performers with birthdate equals") assert.GreaterOrEqual(s.t, equalsResult.Count, 2, "Expected at least 2 performers with birthdate 2000-01-07") // Verify performers 1 and 3 are in results found1 := false found3 := false for _, p := range equalsResult.Performers { if p.ID == performer1.ID { found1 = true } if p.ID == performer3.ID { found3 = true } // Ensure performer2 is not in results assert.NotEqual(s.t, performer2.ID, p.ID, "Performer with different birthdate should not be in EQUALS results") } assert.True(s.t, found1, "Performer 1 with matching birthdate not found") assert.True(s.t, found3, "Performer 3 with matching birthdate not found") // Test GREATER_THAN modifier gtResult, err := s.client.queryPerformers(models.PerformerQueryInput{ Page: 1, PerPage: 100, Direction: models.SortDirectionEnumAsc, Sort: models.PerformerSortEnumName, Birthdate: &models.DateCriterionInput{ Value: "1997-01-01", Modifier: models.CriterionModifierGreaterThan, }, }) assert.NoError(s.t, err, "Error querying performers with birthdate greater than") // Performer1 and Performer3 should be in results (born in 2000) foundGt1 := false foundGt3 := false for _, p := range gtResult.Performers { if p.ID == performer1.ID { foundGt1 = true } if p.ID == performer3.ID { foundGt3 = true } // Performer2 born in 1995 should not be in results assert.NotEqual(s.t, performer2.ID, p.ID, "Performer with birthdate before 1997 should not be in GREATER_THAN results") } assert.True(s.t, foundGt1, "Performer 1 born after 1997 should be in GREATER_THAN results") assert.True(s.t, foundGt3, "Performer 3 born after 1997 should be in GREATER_THAN results") // Test LESS_THAN modifier ltResult, err := s.client.queryPerformers(models.PerformerQueryInput{ Page: 1, PerPage: 100, Direction: models.SortDirectionEnumAsc, Sort: models.PerformerSortEnumName, Birthdate: &models.DateCriterionInput{ Value: "1997-01-01", Modifier: models.CriterionModifierLessThan, }, }) assert.NoError(s.t, err, "Error querying performers with birthdate less than") // Performer2 should be in results (born in 1995) foundLt2 := false for _, p := range ltResult.Performers { if p.ID == performer2.ID { foundLt2 = true } // Performer1 and Performer3 born in 2000 should not be in results assert.NotEqual(s.t, performer1.ID, p.ID, "Performer with birthdate after 1997 should not be in LESS_THAN results") assert.NotEqual(s.t, performer3.ID, p.ID, "Performer with birthdate after 1997 should not be in LESS_THAN results") } assert.True(s.t, foundLt2, "Performer 2 born before 1997 should be in LESS_THAN results") // Test NOT_EQUALS modifier neResult, err := s.client.queryPerformers(models.PerformerQueryInput{ Page: 1, PerPage: 100, Direction: models.SortDirectionEnumAsc, Sort: models.PerformerSortEnumName, Birthdate: &models.DateCriterionInput{ Value: birthdate1, Modifier: models.CriterionModifierNotEquals, }, }) assert.NoError(s.t, err, "Error querying performers with birthdate not equals") // Performer2 should be in results foundNe2 := false for _, p := range neResult.Performers { if p.ID == performer2.ID { foundNe2 = true } // Performer1 and Performer3 should not be in results assert.NotEqual(s.t, performer1.ID, p.ID, "Performer with matching birthdate should not be in NOT_EQUALS results") assert.NotEqual(s.t, performer3.ID, p.ID, "Performer with matching birthdate should not be in NOT_EQUALS results") } assert.True(s.t, foundNe2, "Performer 2 with different birthdate should be in NOT_EQUALS results") } func TestCreatePerformer(t *testing.T) { pt := createPerformerTestRunner(t) pt.testCreatePerformer() } func TestFindPerformer(t *testing.T) { pt := createPerformerTestRunner(t) pt.testFindPerformer() } func TestUpdatePerformer(t *testing.T) { pt := createPerformerTestRunner(t) pt.testUpdatePerformer() } // TestUpdatePerformerName is removed due to no longer allowing // partial updates func TestDestroyPerformer(t *testing.T) { pt := createPerformerTestRunner(t) pt.testDestroyPerformer() } func (s *performerTestRunner) testQueryPerformersByAgeAndBirthYear() { // Use relative dates based on current time so tests don't break as time passes now := time.Now() currentYear := now.Year() // Calculate birthdates for specific ages (use January 1st to ensure birthday has passed) birthYear30 := currentYear - 30 birthYear25 := currentYear - 25 birthYear20 := currentYear - 20 birthdate30YearsAgo := time.Date(birthYear30, 1, 1, 0, 0, 0, 0, time.UTC).Format("2006-01-02") birthdate25YearsAgo := time.Date(birthYear25, 1, 1, 0, 0, 0, 0, time.UTC).Format("2006-01-02") birthdate20YearsAgo := time.Date(birthYear20, 1, 1, 0, 0, 0, 0, time.UTC).Format("2006-01-02") // Death date 5 years ago (so performer born 25 years ago died at age 20) deathdate5YearsAgo := time.Date(currentYear-5, 4, 19, 0, 0, 0, 0, time.UTC).Format("2006-01-02") // Create performer age 30 (alive) name1 := s.generatePerformerName() performer1, err := s.createTestPerformer(&models.PerformerCreateInput{ Name: name1, Birthdate: &birthdate30YearsAgo, }) assert.NoError(s.t, err) // Create performer age 25 (alive) name2 := s.generatePerformerName() performer2, err := s.createTestPerformer(&models.PerformerCreateInput{ Name: name2, Birthdate: &birthdate25YearsAgo, }) assert.NoError(s.t, err) // Create performer born 25 years ago but died 5 years ago (age at death: 20) name3 := s.generatePerformerName() performer3, err := s.createTestPerformer(&models.PerformerCreateInput{ Name: name3, Birthdate: &birthdate25YearsAgo, Deathdate: &deathdate5YearsAgo, }) assert.NoError(s.t, err) // Create performer age 20 (alive) name4 := s.generatePerformerName() performer4, err := s.createTestPerformer(&models.PerformerCreateInput{ Name: name4, Birthdate: &birthdate20YearsAgo, }) assert.NoError(s.t, err) // Test birth_year filter: query for performers born in birthYear25 birthYearFilter25 := &models.IntCriterionInput{ Value: birthYear25, Modifier: models.CriterionModifierEquals, } result, err := s.client.queryPerformers(models.PerformerQueryInput{ BirthYear: birthYearFilter25, Page: 1, PerPage: 100, Direction: models.SortDirectionEnumAsc, Sort: models.PerformerSortEnumName, }) assert.NoError(s.t, err, "Error querying performers by birth year") assert.True(s.t, result.Count >= 2, "Expected at least 2 performers born in year %d", birthYear25) // Verify both performers born in birthYear25 are in results found2 := false found3 := false for _, p := range result.Performers { if p.ID == performer2.ID { found2 = true } if p.ID == performer3.ID { found3 = true } } assert.True(s.t, found2, "Performer born in %d (alive) not found", birthYear25) assert.True(s.t, found3, "Performer born in %d (deceased) not found", birthYear25) // Test birth_year filter: query for performers born in birthYear30 birthYearFilter30 := &models.IntCriterionInput{ Value: birthYear30, Modifier: models.CriterionModifierEquals, } result, err = s.client.queryPerformers(models.PerformerQueryInput{ BirthYear: birthYearFilter30, Page: 1, PerPage: 100, Direction: models.SortDirectionEnumAsc, Sort: models.PerformerSortEnumName, }) assert.NoError(s.t, err, "Error querying performers by birth year %d", birthYear30) assert.True(s.t, result.Count >= 1, "Expected at least 1 performer born in %d", birthYear30) // Verify performer born in birthYear30 is in results found1 := false for _, p := range result.Performers { if p.ID == performer1.ID { found1 = true } } assert.True(s.t, found1, "Performer born in %d not found", birthYear30) // Test age filter: query for performers age 25 (still alive) age25 := &models.IntCriterionInput{ Value: 25, Modifier: models.CriterionModifierEquals, } result, err = s.client.queryPerformers(models.PerformerQueryInput{ Age: age25, Page: 1, PerPage: 100, Direction: models.SortDirectionEnumAsc, Sort: models.PerformerSortEnumName, }) assert.NoError(s.t, err, "Error querying performers by age 25") assert.True(s.t, result.Count >= 1, "Expected at least 1 performer age 25") // Verify performer2 (alive, age 25) is in results found2 = false for _, p := range result.Performers { if p.ID == performer2.ID { found2 = true } // performer3 should NOT be in results (died at age 20) if p.ID == performer3.ID { s.t.Errorf("Performer who died at age 20 should not be in age 25 results") } } assert.True(s.t, found2, "Performer age 25 not found") // Test age filter: query for performers age 20 age20 := &models.IntCriterionInput{ Value: 20, Modifier: models.CriterionModifierEquals, } result, err = s.client.queryPerformers(models.PerformerQueryInput{ Age: age20, Page: 1, PerPage: 100, Direction: models.SortDirectionEnumAsc, Sort: models.PerformerSortEnumName, }) assert.NoError(s.t, err, "Error querying performers by age 20") assert.True(s.t, result.Count >= 2, "Expected at least 2 performers age 20") // Verify both performer3 (died at 20) and performer4 (currently 20) are in results found3 = false found4 := false for _, p := range result.Performers { if p.ID == performer3.ID { found3 = true } if p.ID == performer4.ID { found4 = true } } assert.True(s.t, found3, "Performer who died at age 20 not found") assert.True(s.t, found4, "Performer currently age 20 not found") } func (s *performerTestRunner) testQueryPerformersSceneCountSort() { // Test that performers with 0 scenes are returned when sorting by SCENE_COUNT // Create performer with no scenes performerWithNoScenes, err := s.createTestPerformer(&models.PerformerCreateInput{ Name: s.generatePerformerName(), }) assert.NoError(s.t, err) // Create performer with scenes performerWithScenes, err := s.createTestPerformer(&models.PerformerCreateInput{ Name: s.generatePerformerName(), }) assert.NoError(s.t, err) // Create a scene with the second performer sceneDate := "2020-01-15" sceneTitle := s.generateSceneName() _, err = s.createTestScene(&models.SceneCreateInput{ Title: &sceneTitle, Date: sceneDate, Performers: []models.PerformerAppearanceInput{ { PerformerID: performerWithScenes.UUID(), }, }, }) assert.NoError(s.t, err) // Query performers sorted by SCENE_COUNT DESC (most scenes first) result, err := s.client.queryPerformers(models.PerformerQueryInput{ Page: 1, PerPage: 100, Direction: models.SortDirectionEnumDesc, Sort: models.PerformerSortEnumSceneCount, }) assert.NoError(s.t, err, "Error querying performers by scene count") // Find our test performers in the results foundWithNoScenes := false foundWithScenes := false indexWithNoScenes := -1 indexWithScenes := -1 for i, p := range result.Performers { if p.ID == performerWithNoScenes.ID { foundWithNoScenes = true indexWithNoScenes = i } if p.ID == performerWithScenes.ID { foundWithScenes = true indexWithScenes = i } } // Both performers should be in the results assert.True(s.t, foundWithNoScenes, "Performer with 0 scenes not found when sorting by SCENE_COUNT DESC") assert.True(s.t, foundWithScenes, "Performer with scenes not found when sorting by SCENE_COUNT DESC") // Performer with scenes should come before performer with 0 scenes when sorting DESC if foundWithNoScenes && foundWithScenes { assert.Less(s.t, indexWithScenes, indexWithNoScenes, "Performer with scenes should come before performer with 0 scenes when sorting DESC") } // Query performers sorted by SCENE_COUNT ASC (fewest scenes first) result, err = s.client.queryPerformers(models.PerformerQueryInput{ Page: 1, PerPage: 100, Direction: models.SortDirectionEnumAsc, Sort: models.PerformerSortEnumSceneCount, }) assert.NoError(s.t, err, "Error querying performers by scene count ASC") foundWithNoScenes = false foundWithScenes = false indexWithNoScenes = -1 indexWithScenes = -1 for i, p := range result.Performers { if p.ID == performerWithNoScenes.ID { foundWithNoScenes = true indexWithNoScenes = i } if p.ID == performerWithScenes.ID { foundWithScenes = true indexWithScenes = i } } assert.True(s.t, foundWithNoScenes, "Performer with 0 scenes not found when sorting by SCENE_COUNT ASC") assert.True(s.t, foundWithScenes, "Performer with scenes not found when sorting by SCENE_COUNT ASC") // Performer with 0 scenes should come before performer with scenes when sorting ASC if foundWithNoScenes && foundWithScenes { assert.Less(s.t, indexWithNoScenes, indexWithScenes, "Performer with 0 scenes should come before performer with scenes when sorting ASC") } // Test sorting by DEBUT result, err = s.client.queryPerformers(models.PerformerQueryInput{ Page: 1, PerPage: 100, Direction: models.SortDirectionEnumDesc, Sort: models.PerformerSortEnumDebut, }) assert.NoError(s.t, err, "Error querying performers by debut") foundWithNoScenes = false foundWithScenes = false for _, p := range result.Performers { if p.ID == performerWithNoScenes.ID { foundWithNoScenes = true } if p.ID == performerWithScenes.ID { foundWithScenes = true } } assert.True(s.t, foundWithNoScenes, "Performer with 0 scenes not found when sorting by DEBUT") assert.True(s.t, foundWithScenes, "Performer with scenes not found when sorting by DEBUT") // Test sorting by LAST_SCENE result, err = s.client.queryPerformers(models.PerformerQueryInput{ Page: 1, PerPage: 100, Direction: models.SortDirectionEnumDesc, Sort: models.PerformerSortEnumLastScene, }) assert.NoError(s.t, err, "Error querying performers by last scene") foundWithNoScenes = false foundWithScenes = false for _, p := range result.Performers { if p.ID == performerWithNoScenes.ID { foundWithNoScenes = true } if p.ID == performerWithScenes.ID { foundWithScenes = true } } assert.True(s.t, foundWithNoScenes, "Performer with 0 scenes not found when sorting by LAST_SCENE") assert.True(s.t, foundWithScenes, "Performer with scenes not found when sorting by LAST_SCENE") // Verify count matches actual performer count totalCount := len(result.Performers) assert.Equal(s.t, result.Count, totalCount, "Count field should match number of performers returned") } func TestQueryPerformers(t *testing.T) { pt := createPerformerTestRunner(t) pt.testQueryPerformers() } func TestQueryPerformersBirthdate(t *testing.T) { pt := createPerformerTestRunner(t) pt.testQueryPerformersBirthdate() } func TestQueryPerformersByAgeAndBirthYear(t *testing.T) { pt := createPerformerTestRunner(t) pt.testQueryPerformersByAgeAndBirthYear() } func TestQueryPerformersSceneCountSort(t *testing.T) { pt := createPerformerTestRunner(t) pt.testQueryPerformersSceneCountSort() } ================================================ FILE: internal/api/performer_resolver_integration_test.go ================================================ //go:build integration package api_test import ( "testing" "time" "github.com/stashapp/stash-box/internal/models" "github.com/stretchr/testify/assert" ) type performerResolverTestRunner struct { testRunner } func createPerformerResolverTestRunner(t *testing.T) *performerResolverTestRunner { return &performerResolverTestRunner{ testRunner: *asAdmin(t), } } // testPerformerImages tests the images resolver field func (s *performerResolverTestRunner) testPerformerImages() { // Create a performer using the resolver name := s.generatePerformerName() performer, err := s.resolver.Mutation().PerformerCreate(s.ctx, models.PerformerCreateInput{ Name: name, }) assert.NoError(s.t, err) // Get images via resolver images, err := s.resolver.Performer().Images(s.ctx, performer) assert.NoError(s.t, err) assert.Nil(s.t, images, "New performer should have nil images") } // testPerformerDeleted tests the deleted field func (s *performerResolverTestRunner) testPerformerDeleted() { // Create a performer name := s.generatePerformerName() performer, err := s.resolver.Mutation().PerformerCreate(s.ctx, models.PerformerCreateInput{ Name: name, }) assert.NoError(s.t, err) // Verify not deleted assert.Equal(s.t, false, performer.Deleted, "New performer should not be deleted") // Destroy the performer performerID := performer.ID destroyed, err := s.resolver.Mutation().PerformerDestroy(s.ctx, models.PerformerDestroyInput{ ID: performerID, }) assert.NoError(s.t, err) assert.True(s.t, destroyed, "Performer should be destroyed") // Find the performer again (it should still exist but marked as deleted) deletedPerformer, err := s.resolver.Query().FindPerformer(s.ctx, performerID) assert.NoError(s.t, err) // The performer should be nil (destroyed performers are not returned) assert.Nil(s.t, deletedPerformer, "Deleted performer should not be returned") } // testPerformerEdits tests the edits resolver field func (s *performerResolverTestRunner) testPerformerEdits() { // Create a performer via edit name := s.generatePerformerName() edit, err := s.createTestPerformerEdit(models.OperationEnumCreate, &models.PerformerEditDetailsInput{ Name: &name, }, nil, nil) assert.NoError(s.t, err) // Apply the edit appliedEdit, err := s.applyEdit(edit.ID) assert.NoError(s.t, err) // Get the created performer ID from the edit target, err := s.resolver.Edit().Target(s.ctx, appliedEdit) assert.NoError(s.t, err) performer := target.(*models.Performer) // Get edits via resolver edits, err := s.resolver.Performer().Edits(s.ctx, performer) assert.NoError(s.t, err) assert.NotNil(s.t, edits, "Edits should not be nil") assert.True(s.t, len(edits) >= 1, "Performer should have at least one edit") // Verify the edit we created is in the list foundEdit := false for _, e := range edits { if e.ID == edit.ID { foundEdit = true break } } assert.True(s.t, foundEdit, "Should find the create edit in performer's edits") } // testPerformerSceneCount tests the scene_count resolver field func (s *performerResolverTestRunner) testPerformerSceneCount() { // Create a performer name := s.generatePerformerName() performer, err := s.resolver.Mutation().PerformerCreate(s.ctx, models.PerformerCreateInput{ Name: name, }) assert.NoError(s.t, err) // Initially should have 0 scenes sceneCount, err := s.resolver.Performer().SceneCount(s.ctx, performer) assert.NoError(s.t, err) assert.Equal(s.t, 0, sceneCount, "New performer should have 0 scenes") // Create a scene with this performer performerID := performer.ID scene, err := s.resolver.Mutation().SceneCreate(s.ctx, models.SceneCreateInput{ Date: "2020-01-01", Performers: []models.PerformerAppearanceInput{ { PerformerID: performerID, }, }, }) assert.NoError(s.t, err) assert.NotNil(s.t, scene) // Refresh the performer performer, err = s.resolver.Query().FindPerformer(s.ctx, performerID) assert.NoError(s.t, err) // Now should have 1 scene sceneCount, err = s.resolver.Performer().SceneCount(s.ctx, performer) assert.NoError(s.t, err) assert.Equal(s.t, 1, sceneCount, "Performer should have 1 scene") } // testPerformerScenes tests the scenes resolver field func (s *performerResolverTestRunner) testPerformerScenes() { // Create a performer name := s.generatePerformerName() performer, err := s.resolver.Mutation().PerformerCreate(s.ctx, models.PerformerCreateInput{ Name: name, }) assert.NoError(s.t, err) performerID := performer.ID // Create two scenes with this performer scene1, err := s.resolver.Mutation().SceneCreate(s.ctx, models.SceneCreateInput{ Date: "2020-01-01", Performers: []models.PerformerAppearanceInput{ {PerformerID: performerID}, }, }) assert.NoError(s.t, err) scene2, err := s.resolver.Mutation().SceneCreate(s.ctx, models.SceneCreateInput{ Date: "2020-02-02", Performers: []models.PerformerAppearanceInput{ {PerformerID: performerID}, }, }) assert.NoError(s.t, err) // Refresh the performer performer, err = s.resolver.Query().FindPerformer(s.ctx, performerID) assert.NoError(s.t, err) // Get scenes via resolver scenes, err := s.resolver.Performer().Scenes(s.ctx, performer, nil) assert.NoError(s.t, err) assert.NotNil(s.t, scenes, "Scenes should not be nil") assert.True(s.t, len(scenes) >= 2, "Performer should have at least 2 scenes") // Verify our scenes are in the list foundScene1 := false foundScene2 := false for _, scene := range scenes { if scene.ID == scene1.ID { foundScene1 = true } if scene.ID == scene2.ID { foundScene2 = true } } assert.True(s.t, foundScene1, "Should find scene1 in performer's scenes") assert.True(s.t, foundScene2, "Should find scene2 in performer's scenes") } // testPerformerStudios tests the studios resolver field func (s *performerResolverTestRunner) testPerformerStudios() { // Create a performer name := s.generatePerformerName() performer, err := s.resolver.Mutation().PerformerCreate(s.ctx, models.PerformerCreateInput{ Name: name, }) assert.NoError(s.t, err) performerID := performer.ID // Create two different studios studio1Name := s.generateStudioName() studio1, err := s.resolver.Mutation().StudioCreate(s.ctx, models.StudioCreateInput{ Name: studio1Name, }) assert.NoError(s.t, err) studio2Name := s.generateStudioName() studio2, err := s.resolver.Mutation().StudioCreate(s.ctx, models.StudioCreateInput{ Name: studio2Name, }) assert.NoError(s.t, err) // Create scenes with this performer at different studios // Scene at studio1 _, err = s.resolver.Mutation().SceneCreate(s.ctx, models.SceneCreateInput{ Date: "2020-01-01", StudioID: &studio1.ID, Performers: []models.PerformerAppearanceInput{ {PerformerID: performerID}, }, }) assert.NoError(s.t, err) // Scene at studio2 _, err = s.resolver.Mutation().SceneCreate(s.ctx, models.SceneCreateInput{ Date: "2020-02-02", StudioID: &studio2.ID, Performers: []models.PerformerAppearanceInput{ {PerformerID: performerID}, }, }) assert.NoError(s.t, err) // Refresh the performer performer, err = s.resolver.Query().FindPerformer(s.ctx, performerID) assert.NoError(s.t, err) // Get studios via resolver (nil studioID returns all studios) studios, err := s.resolver.Performer().Studios(s.ctx, performer, nil) assert.NoError(s.t, err) assert.NotNil(s.t, studios, "Studios should not be nil") assert.True(s.t, len(studios) >= 2, "Performer should have appeared with at least 2 studios") // Verify our studios are in the list foundStudio1 := false foundStudio2 := false for _, ps := range studios { if ps.Studio.ID == studio1.ID { foundStudio1 = true assert.True(s.t, ps.SceneCount >= 1, "Studio1 should have at least 1 scene with this performer") } if ps.Studio.ID == studio2.ID { foundStudio2 = true assert.True(s.t, ps.SceneCount >= 1, "Studio2 should have at least 1 scene with this performer") } } assert.True(s.t, foundStudio1, "Should find studio1 in performer's studios") assert.True(s.t, foundStudio2, "Should find studio2 in performer's studios") } // testPerformerCreatedUpdated tests the created and updated timestamp fields func (s *performerResolverTestRunner) testPerformerCreatedUpdated() { // Create a performer name := s.generatePerformerName() performer, err := s.resolver.Mutation().PerformerCreate(s.ctx, models.PerformerCreateInput{ Name: name, }) assert.NoError(s.t, err) // Get created and updated timestamps - these are direct fields createdTime := performer.Created updatedTime := performer.Updated // Initially, updated should equal created assert.Equal(s.t, createdTime, updatedTime, "Updated should equal created for new performer") // Wait a bit to ensure timestamps are different time.Sleep(10 * time.Millisecond) // Update the performer performerID := performer.ID newAliases := []string{"Updated Alias"} ctx := s.updateContext([]string{"aliases"}) updatedPerformer, err := s.resolver.Mutation().PerformerUpdate(ctx, models.PerformerUpdateInput{ ID: performerID, Aliases: newAliases, }) assert.NoError(s.t, err) // Get new timestamps newCreatedTime := updatedPerformer.Created newUpdatedTime := updatedPerformer.Updated // Verify updated timestamp changed assert.True(s.t, newUpdatedTime.After(updatedTime), "Updated timestamp should be after original") // Created should remain the same assert.Equal(s.t, newCreatedTime, createdTime, "Created timestamp should not change on update") } // testPerformerAge tests the age calculated field func (s *performerResolverTestRunner) testPerformerAge() { // Create a performer with a known birthdate birthdate := "2000-01-01" name := s.generatePerformerName() performer, err := s.resolver.Mutation().PerformerCreate(s.ctx, models.PerformerCreateInput{ Name: name, Birthdate: &birthdate, }) assert.NoError(s.t, err) // Get age via resolver age, err := s.resolver.Performer().Age(s.ctx, performer) assert.NoError(s.t, err) // Age should be approximately current year - 2000 currentYear := time.Now().Year() expectedAge := currentYear - 2000 assert.NotNil(s.t, age, "Age should not be nil for performer with birthdate") assert.True(s.t, *age >= expectedAge-1 && *age <= expectedAge+1, "Age should be approximately %d, got %d", expectedAge, *age) // Create a performer without birthdate name2 := s.generatePerformerName() performerNoBirthdate, err := s.resolver.Mutation().PerformerCreate(s.ctx, models.PerformerCreateInput{ Name: name2, }) assert.NoError(s.t, err) // Age should be nil ageNil, err := s.resolver.Performer().Age(s.ctx, performerNoBirthdate) assert.NoError(s.t, err) assert.Nil(s.t, ageNil, "Age should be nil for performer without birthdate") // Create a performer with a deathdate deathdate := "2020-06-15" name3 := s.generatePerformerName() performerDeceased, err := s.resolver.Mutation().PerformerCreate(s.ctx, models.PerformerCreateInput{ Name: name3, Birthdate: &birthdate, Deathdate: &deathdate, }) assert.NoError(s.t, err) // Age should be calculated from birthdate to deathdate ageDeceased, err := s.resolver.Performer().Age(s.ctx, performerDeceased) assert.NoError(s.t, err) assert.NotNil(s.t, ageDeceased, "Age should not be nil for deceased performer with both dates") // Age at death should be 20 (2020 - 2000) assert.Equal(s.t, *ageDeceased, 20, "Age at death should be 20") } // testPerformerAliases tests the aliases resolver field func (s *performerResolverTestRunner) testPerformerAliases() { // Create a performer with aliases aliases := []string{"Alias One", "Alias Two", "Alias Three"} name := s.generatePerformerName() performer, err := s.resolver.Mutation().PerformerCreate(s.ctx, models.PerformerCreateInput{ Name: name, Aliases: aliases, }) assert.NoError(s.t, err) // Get aliases via resolver retrievedAliases, err := s.resolver.Performer().Aliases(s.ctx, performer) assert.NoError(s.t, err) assert.ElementsMatch(s.t, retrievedAliases, aliases) // Create performer without aliases name2 := s.generatePerformerName() performerNoAliases, err := s.resolver.Mutation().PerformerCreate(s.ctx, models.PerformerCreateInput{ Name: name2, }) assert.NoError(s.t, err) // Should have no aliases emptyAliases, err := s.resolver.Performer().Aliases(s.ctx, performerNoAliases) assert.NoError(s.t, err) assert.Equal(s.t, len(emptyAliases), 0, "Performer without aliases should have no aliases") } // testPerformerUrls tests the urls resolver field func (s *performerResolverTestRunner) testPerformerUrls() { // Create a site for URLs siteName := s.generateSiteName() site, err := s.resolver.Mutation().SiteCreate(s.ctx, models.SiteCreateInput{ Name: siteName, }) assert.NoError(s.t, err) // Create a performer with URLs urls := []models.URL{ {URL: "http://example.com/performer1", SiteID: site.ID}, {URL: "http://example.com/performer2", SiteID: site.ID}, } name := s.generatePerformerName() performer, err := s.resolver.Mutation().PerformerCreate(s.ctx, models.PerformerCreateInput{ Name: name, Urls: urls, }) assert.NoError(s.t, err) // Get URLs via resolver retrievedUrls, err := s.resolver.Performer().Urls(s.ctx, performer) assert.NoError(s.t, err) assert.Equal(s.t, len(retrievedUrls), len(urls), "Should have same number of URLs") // Verify URLs match for i, url := range retrievedUrls { assert.Equal(s.t, url.URL, urls[i].URL, "URL should match") assert.Equal(s.t, url.SiteID, urls[i].SiteID, "Site ID should match") } } // testPerformerBirthdate tests the birthdate resolver field func (s *performerResolverTestRunner) testPerformerBirthdate() { // Create a performer with a birthdate birthdate := "2000-05-15" name := s.generatePerformerName() performer, err := s.resolver.Mutation().PerformerCreate(s.ctx, models.PerformerCreateInput{ Name: name, Birthdate: &birthdate, }) assert.NoError(s.t, err) // Get birthdate via resolver retrievedBirthdate, err := s.resolver.Performer().Birthdate(s.ctx, performer) assert.NoError(s.t, err) assert.NotNil(s.t, retrievedBirthdate, "Birthdate should not be nil") assert.Equal(s.t, retrievedBirthdate.Date, birthdate, "Birthdate should match") // Create performer without birthdate name2 := s.generatePerformerName() performerNoBirthdate, err := s.resolver.Mutation().PerformerCreate(s.ctx, models.PerformerCreateInput{ Name: name2, }) assert.NoError(s.t, err) // Should be nil nilBirthdate, err := s.resolver.Performer().Birthdate(s.ctx, performerNoBirthdate) assert.NoError(s.t, err) assert.Nil(s.t, nilBirthdate, "Birthdate should be nil for performer without birthdate") } // testPerformerTattoosAndPiercings tests the tattoos and piercings resolver fields func (s *performerResolverTestRunner) testPerformerTattoosAndPiercings() { tattooDesc := "Dragon on back" piercingDesc := "Silver ring" // Create a performer with tattoos and piercings tattoos := []models.BodyModificationInput{ {Location: "Back", Description: &tattooDesc}, {Location: "Arm", Description: nil}, } piercings := []models.BodyModificationInput{ {Location: "Nose", Description: &piercingDesc}, {Location: "Navel", Description: nil}, } name := s.generatePerformerName() performer, err := s.resolver.Mutation().PerformerCreate(s.ctx, models.PerformerCreateInput{ Name: name, Tattoos: tattoos, Piercings: piercings, }) assert.NoError(s.t, err) // Get tattoos via resolver retrievedTattoos, err := s.resolver.Performer().Tattoos(s.ctx, performer) assert.NoError(s.t, err) assertBodyMods(s.t, tattoos, retrievedTattoos, "Tattoos should match") // Get piercings via resolver retrievedPiercings, err := s.resolver.Performer().Piercings(s.ctx, performer) assert.NoError(s.t, err) assert.Equal(s.t, len(retrievedPiercings), len(piercings), "Should have same number of piercings") assertBodyMods(s.t, piercings, retrievedPiercings, "Piercings should match") } func TestPerformerImages(t *testing.T) { pt := createPerformerResolverTestRunner(t) pt.testPerformerImages() } func TestPerformerDeleted(t *testing.T) { pt := createPerformerResolverTestRunner(t) pt.testPerformerDeleted() } func TestPerformerEdits(t *testing.T) { pt := createPerformerResolverTestRunner(t) pt.testPerformerEdits() } func TestPerformerSceneCount(t *testing.T) { pt := createPerformerResolverTestRunner(t) pt.testPerformerSceneCount() } func TestPerformerScenes(t *testing.T) { pt := createPerformerResolverTestRunner(t) pt.testPerformerScenes() } func TestPerformerStudios(t *testing.T) { pt := createPerformerResolverTestRunner(t) pt.testPerformerStudios() } func TestPerformerCreatedUpdated(t *testing.T) { pt := createPerformerResolverTestRunner(t) pt.testPerformerCreatedUpdated() } func TestPerformerAge(t *testing.T) { pt := createPerformerResolverTestRunner(t) pt.testPerformerAge() } func TestPerformerAliases(t *testing.T) { pt := createPerformerResolverTestRunner(t) pt.testPerformerAliases() } func TestPerformerUrls(t *testing.T) { pt := createPerformerResolverTestRunner(t) pt.testPerformerUrls() } func TestPerformerBirthdate(t *testing.T) { pt := createPerformerResolverTestRunner(t) pt.testPerformerBirthdate() } func TestPerformerTattoosAndPiercings(t *testing.T) { pt := createPerformerResolverTestRunner(t) pt.testPerformerTattoosAndPiercings() } ================================================ FILE: internal/api/resolver.go ================================================ package api import ( "context" "github.com/stashapp/stash-box/internal/config" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/internal/service" ) type Resolver struct { services service.Factory } func NewResolver(fac service.Factory) *Resolver { return &Resolver{ services: fac, } } func (r *Resolver) Mutation() models.MutationResolver { return &mutationResolver{r} } func (r *Resolver) Edit() models.EditResolver { return &editResolver{r} } func (r *Resolver) EditComment() models.EditCommentResolver { return &editCommentResolver{r} } func (r *Resolver) EditVote() models.EditVoteResolver { return &editVoteResolver{r} } func (r *Resolver) Performer() models.PerformerResolver { return &performerResolver{r} } func (r *Resolver) PerformerEdit() models.PerformerEditResolver { return &performerEditResolver{r} } func (r *Resolver) StudioEdit() models.StudioEditResolver { return &studioEditResolver{r} } func (r *Resolver) TagEdit() models.TagEditResolver { return &tagEditResolver{r} } func (r *Resolver) SceneEdit() models.SceneEditResolver { return &sceneEditResolver{r} } func (r *Resolver) Tag() models.TagResolver { return &tagResolver{r} } func (r *Resolver) TagCategory() models.TagCategoryResolver { return &tagCategoryResolver{r} } func (r *Resolver) Image() models.ImageResolver { return &imageResolver{r} } func (r *Resolver) Studio() models.StudioResolver { return &studioResolver{r} } func (r *Resolver) Scene() models.SceneResolver { return &sceneResolver{r} } func (r *Resolver) Site() models.SiteResolver { return &siteResolver{r} } func (r *Resolver) URL() models.URLResolver { return &urlResolver{r} } func (r *Resolver) User() models.UserResolver { return &userResolver{r} } func (r *Resolver) Query() models.QueryResolver { return &queryResolver{r} } func (r *Resolver) QueryPerformersResultType() models.QueryPerformersResultTypeResolver { return &queryPerformerResolver{r} } func (r *Resolver) QueryScenesResultType() models.QueryScenesResultTypeResolver { return &querySceneResolver{r} } func (r *Resolver) QueryEditsResultType() models.QueryEditsResultTypeResolver { return &queryEditResolver{r} } func (r *Resolver) Draft() models.DraftResolver { return &draftResolver{r} } func (r *Resolver) PerformerDraft() models.PerformerDraftResolver { return &performerDraftResolver{r} } func (r *Resolver) SceneDraft() models.SceneDraftResolver { return &sceneDraftResolver{r} } func (r *Resolver) QueryExistingSceneResult() models.QueryExistingSceneResultResolver { return &queryExistingSceneResolver{r} } func (r *Resolver) QueryExistingPerformerResult() models.QueryExistingPerformerResultResolver { return &queryExistingPerformerResolver{r} } func (r *Resolver) QueryNotificationsResult() models.QueryNotificationsResultResolver { return &queryNotificationsResolver{r} } func (r *Resolver) Notification() models.NotificationResolver { return ¬ificationResolver{r} } func (r *Resolver) QueryModAuditsResultType() models.QueryModAuditsResultTypeResolver { return &queryModAuditResolver{r} } func (r *Resolver) ModAudit() models.ModAuditResolver { return &modAuditResolver{r} } type mutationResolver struct{ *Resolver } type queryResolver struct{ *Resolver } func (r *queryResolver) Version(ctx context.Context) (*models.Version, error) { version, githash, buildstamp := GetVersion() return &models.Version{ Version: version, Hash: githash, BuildTime: buildstamp, BuildType: buildtype, }, nil } func (r *queryResolver) GetConfig(ctx context.Context) (*models.StashBoxConfig, error) { return &models.StashBoxConfig{ HostURL: config.GetHostURL(), RequireInvite: config.GetRequireInvite(), RequireActivation: config.GetRequireActivation(), VotePromotionThreshold: config.GetVotePromotionThreshold(), VoteApplicationThreshold: config.GetVoteApplicationThreshold(), VotingPeriod: config.GetVotingPeriod(), MinDestructiveVotingPeriod: config.GetMinDestructiveVotingPeriod(), VoteCronInterval: config.GetVoteCronInterval(), GuidelinesURL: config.GetGuidelinesURL(), RequireSceneDraft: config.GetRequireSceneDraft(), EditUpdateLimit: config.GetEditUpdateLimit(), RequireTagRole: config.GetRequireTagRole(), }, nil } ================================================ FILE: internal/api/resolver_model_draft.go ================================================ package api import ( "context" "fmt" "time" "github.com/stashapp/stash-box/internal/config" "github.com/stashapp/stash-box/internal/models" ) type draftResolver struct{ *Resolver } func (r *draftResolver) Created(ctx context.Context, obj *models.Draft) (*time.Time, error) { return &obj.CreatedAt, nil } func (r *draftResolver) Expires(ctx context.Context, obj *models.Draft) (*time.Time, error) { duration := time.Second * time.Duration(config.GetDraftTimeLimit()) expiration := obj.CreatedAt.Add(duration) return &expiration, nil } func (r *draftResolver) Data(ctx context.Context, obj *models.Draft) (models.DraftData, error) { switch obj.Type { case "SCENE": return obj.GetSceneData() case "PERFORMER": return obj.GetPerformerData() default: return nil, fmt.Errorf("unsupported type: %s", obj.Type) } } ================================================ FILE: internal/api/resolver_model_edit.go ================================================ package api import ( "context" "time" "github.com/stashapp/stash-box/internal/auth" "github.com/stashapp/stash-box/internal/config" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/pkg/utils" ) type editResolver struct{ *Resolver } func (r *editResolver) ID(ctx context.Context, obj *models.Edit) (string, error) { return obj.ID.String(), nil } func (r *editResolver) User(ctx context.Context, obj *models.Edit) (*models.User, error) { if obj.UserID.UUID.IsNil() { return nil, nil } return r.services.User().FindByID(ctx, obj.UserID.UUID) } func (r *editResolver) Created(ctx context.Context, obj *models.Edit) (*time.Time, error) { return &obj.CreatedAt, nil } func (r *editResolver) Updated(ctx context.Context, obj *models.Edit) (*time.Time, error) { return obj.UpdatedAt, nil } func (r *editResolver) Closed(ctx context.Context, obj *models.Edit) (*time.Time, error) { return obj.ClosedAt, nil } func (r *editResolver) Expires(ctx context.Context, obj *models.Edit) (*time.Time, error) { if obj.Status != models.VoteStatusEnumPending.String() { return nil, nil } // Count expiration time from creation, or time when edit was amended startTime := obj.CreatedAt if obj.UpdatedAt != nil { startTime = *obj.UpdatedAt } // Pending edits that have reached the voting threshold have shorter voting periods. // This will happen for destructive edits, or when votes are not unanimous. short := config.GetVoteApplicationThreshold() > 0 && obj.VoteCount >= config.GetVoteApplicationThreshold() duration := config.GetVotingPeriod() if short { duration = config.GetMinDestructiveVotingPeriod() } expiration := startTime.Add(time.Second * time.Duration(duration)) return &expiration, nil } func (r *editResolver) Target(ctx context.Context, obj *models.Edit) (models.EditTarget, error) { var operation models.OperationEnum var status models.VoteStatusEnum utils.ResolveEnumString(obj.Operation, &operation) utils.ResolveEnumString(obj.Status, &status) if operation == models.OperationEnumCreate && status != models.VoteStatusEnumAccepted && status != models.VoteStatusEnumImmediateAccepted { return nil, nil } return r.services.Edit().GetEditTarget(ctx, obj.ID) } func (r *editResolver) TargetType(ctx context.Context, obj *models.Edit) (models.TargetTypeEnum, error) { var ret models.TargetTypeEnum if !utils.ResolveEnumString(obj.TargetType, &ret) { return "", nil } return ret, nil } func (r *editResolver) MergeSources(ctx context.Context, obj *models.Edit) ([]models.EditTarget, error) { editData := obj.GetData() if editData == nil { return nil, nil } if len(editData.MergeSources) == 0 { return nil, nil } return r.services.Edit().GetMergeSources(ctx, editData.MergeSources, obj.TargetType) } func (r *editResolver) Operation(ctx context.Context, obj *models.Edit) (models.OperationEnum, error) { var ret models.OperationEnum if !utils.ResolveEnumString(obj.Operation, &ret) { return "", nil } return ret, nil } func (r *editResolver) Details(ctx context.Context, obj *models.Edit) (models.EditDetails, error) { var ret models.EditDetails var targetType models.TargetTypeEnum utils.ResolveEnumString(obj.TargetType, &targetType) switch targetType { case models.TargetTypeEnumTag: tagData, err := obj.GetTagData() if err != nil { return nil, err } if tagData.New != nil { tagData.New.EditID = obj.ID } ret = tagData.New case models.TargetTypeEnumPerformer: performerData, err := obj.GetPerformerData() if err != nil { return nil, err } if performerData.New != nil { performerData.New.EditID = obj.ID } ret = performerData.New case models.TargetTypeEnumStudio: studioData, err := obj.GetStudioData() if err != nil { return nil, err } if studioData.New != nil { studioData.New.EditID = obj.ID } ret = studioData.New case models.TargetTypeEnumScene: sceneData, err := obj.GetSceneData() if err != nil { return nil, err } if sceneData.New != nil { sceneData.New.EditID = obj.ID } ret = sceneData.New } return ret, nil } func (r *editResolver) OldDetails(ctx context.Context, obj *models.Edit) (models.EditDetails, error) { var ret models.EditDetails var targetType models.TargetTypeEnum utils.ResolveEnumString(obj.TargetType, &targetType) switch targetType { case models.TargetTypeEnumTag: tagData, err := obj.GetTagData() if err != nil { return nil, err } ret = tagData.Old case models.TargetTypeEnumPerformer: performerData, err := obj.GetPerformerData() if err != nil { return nil, err } ret = performerData.Old case models.TargetTypeEnumStudio: studioData, err := obj.GetStudioData() if err != nil { return nil, err } ret = studioData.Old case models.TargetTypeEnumScene: sceneData, err := obj.GetSceneData() if err != nil { return nil, err } ret = sceneData.Old } return ret, nil } func (r *editResolver) Comments(ctx context.Context, obj *models.Edit) ([]models.EditComment, error) { return r.services.Edit().GetComments(ctx, obj.ID) } func (r *editResolver) Votes(ctx context.Context, obj *models.Edit) ([]models.EditVote, error) { return r.services.Edit().GetVotes(ctx, obj.ID) } func (r *editResolver) Status(ctx context.Context, obj *models.Edit) (models.VoteStatusEnum, error) { var ret models.VoteStatusEnum if !utils.ResolveEnumString(obj.Status, &ret) { return "", nil } return ret, nil } func (r *editResolver) Options(ctx context.Context, obj *models.Edit) (*models.PerformerEditOptions, error) { if obj.TargetType == models.TargetTypeEnumPerformer.String() { data, err := obj.GetPerformerData() if err != nil { return nil, err } options := models.PerformerEditOptions{ SetMergeAliases: data.SetMergeAliases, SetModifyAliases: data.SetModifyAliases, } return &options, nil } return nil, nil } func (r *editResolver) Destructive(ctx context.Context, obj *models.Edit) (bool, error) { return obj.IsDestructive(), nil } func (r *editResolver) Updatable(ctx context.Context, obj *models.Edit) (bool, error) { user := auth.GetCurrentUser(ctx) if user.ID != obj.UserID.UUID { return false, nil } if obj.UpdateCount >= config.GetEditUpdateLimit() { return false, nil } if obj.Operation == models.OperationEnumDestroy.String() { return false, nil } return true, nil } ================================================ FILE: internal/api/resolver_model_edit_comment.go ================================================ package api import ( "context" "time" "github.com/stashapp/stash-box/internal/models" ) type editCommentResolver struct{ *Resolver } func (r *editCommentResolver) ID(ctx context.Context, obj *models.EditComment) (string, error) { return obj.ID.String(), nil } func (r *editCommentResolver) Comment(ctx context.Context, obj *models.EditComment) (string, error) { return obj.Text, nil } func (r *editCommentResolver) Date(ctx context.Context, obj *models.EditComment) (*time.Time, error) { return &obj.CreatedAt, nil } func (r *editCommentResolver) User(ctx context.Context, obj *models.EditComment) (*models.User, error) { if obj.UserID.UUID.IsNil() { return nil, nil } return r.services.User().FindByID(ctx, obj.UserID.UUID) } func (r *editCommentResolver) Edit(ctx context.Context, obj *models.EditComment) (*models.Edit, error) { return r.services.Edit().FindByID(ctx, obj.EditID) } ================================================ FILE: internal/api/resolver_model_edit_vote.go ================================================ package api import ( "context" "time" "github.com/stashapp/stash-box/internal/auth" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/pkg/utils" ) type editVoteResolver struct{ *Resolver } func (r *editVoteResolver) Vote(ctx context.Context, obj *models.EditVote) (models.VoteTypeEnum, error) { var ret models.VoteTypeEnum if !utils.ResolveEnumString(obj.Vote, &ret) { return "", nil } return ret, nil } func (r *editVoteResolver) Date(ctx context.Context, obj *models.EditVote) (*time.Time, error) { return &obj.CreatedAt, nil } func (r *editVoteResolver) User(ctx context.Context, obj *models.EditVote) (*models.User, error) { // User votes only available to users with vote permission if err := auth.ValidateRole(ctx, models.RoleEnumVote); err != nil { return nil, nil } return r.services.User().FindByID(ctx, obj.UserID) } ================================================ FILE: internal/api/resolver_model_image.go ================================================ package api import ( "context" "github.com/stashapp/stash-box/internal/models" ) type imageResolver struct{ *Resolver } func (r *imageResolver) ID(ctx context.Context, obj *models.Image) (string, error) { return obj.ID.String(), nil } func (r *imageResolver) URL(ctx context.Context, obj *models.Image) (string, error) { baseURL := ctx.Value(BaseURLCtxKey).(string) id := obj.ID.String() return baseURL + "/images/" + id, nil } ================================================ FILE: internal/api/resolver_model_notification.go ================================================ package api import ( "context" "time" "github.com/stashapp/stash-box/internal/dataloader" "github.com/stashapp/stash-box/internal/models" ) type notificationResolver struct{ *Resolver } func (r *notificationResolver) Created(ctx context.Context, obj *models.Notification) (*time.Time, error) { return &obj.CreatedAt, nil } func (r *notificationResolver) Read(ctx context.Context, obj *models.Notification) (bool, error) { return obj.ReadAt != nil, nil } func (r *notificationResolver) Data(ctx context.Context, obj *models.Notification) (models.NotificationData, error) { switch obj.Type { case models.NotificationEnumCommentCommentedEdit: fallthrough case models.NotificationEnumCommentOwnEdit: fallthrough case models.NotificationEnumCommentVotedEdit: comment, err := dataloader.For(ctx).EditCommentByID.Load(obj.TargetID) if err != nil { return nil, err } switch obj.Type { case models.NotificationEnumCommentCommentedEdit: return &models.CommentCommentedEdit{Comment: comment}, nil case models.NotificationEnumCommentOwnEdit: return &models.CommentOwnEdit{Comment: comment}, nil default: return &models.CommentVotedEdit{Comment: comment}, nil } case models.NotificationEnumFavoritePerformerScene: fallthrough case models.NotificationEnumFavoriteStudioScene: scene, err := dataloader.For(ctx).SceneByID.Load(obj.TargetID) if err != nil { return nil, err } if obj.Type == models.NotificationEnumFavoritePerformerScene { return &models.FavoritePerformerScene{Scene: scene}, nil } return &models.FavoriteStudioScene{Scene: scene}, nil case models.NotificationEnumFavoritePerformerEdit: fallthrough case models.NotificationEnumFavoriteStudioEdit: fallthrough case models.NotificationEnumDownvoteOwnEdit: fallthrough case models.NotificationEnumFailedOwnEdit: fallthrough case models.NotificationEnumFingerprintedSceneEdit: fallthrough case models.NotificationEnumUpdatedEdit: edit, err := dataloader.For(ctx).EditByID.Load(obj.TargetID) if err != nil { return nil, err } // nolint:exhaustive switch obj.Type { case models.NotificationEnumFavoritePerformerEdit: return &models.FavoritePerformerEdit{Edit: edit}, nil case models.NotificationEnumFavoriteStudioEdit: return &models.FavoriteStudioEdit{Edit: edit}, nil case models.NotificationEnumDownvoteOwnEdit: return &models.DownvoteOwnEdit{Edit: edit}, nil case models.NotificationEnumFailedOwnEdit: return &models.FailedOwnEdit{Edit: edit}, nil case models.NotificationEnumUpdatedEdit: return &models.UpdatedEdit{Edit: edit}, nil case models.NotificationEnumFingerprintedSceneEdit: return &models.FingerprintedSceneEdit{Edit: edit}, nil } } return nil, nil } ================================================ FILE: internal/api/resolver_model_performer.go ================================================ package api import ( "context" "fmt" "sort" "time" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/dataloader" "github.com/stashapp/stash-box/internal/image" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/pkg/utils" ) type performerResolver struct{ *Resolver } func (r *performerResolver) ID(ctx context.Context, obj *models.Performer) (string, error) { return obj.ID.String(), nil } func (r *performerResolver) Aliases(ctx context.Context, obj *models.Performer) ([]string, error) { aliases, err := dataloader.For(ctx).PerformerAliasesByID.Load(obj.ID) if err != nil { return nil, err } sort.Strings(aliases) return aliases, nil } func (r *performerResolver) Urls(ctx context.Context, obj *models.Performer) ([]models.URL, error) { return dataloader.For(ctx).PerformerUrlsByID.Load(obj.ID) } // Deprecated: use `BirthDate` func (r *performerResolver) Birthdate(ctx context.Context, obj *models.Performer) (*models.FuzzyDate, error) { return resolveFuzzyDate(obj.BirthDate), nil } func (r *performerResolver) Age(ctx context.Context, obj *models.Performer) (*int, error) { if obj.BirthDate == nil { return nil, nil } birthdate, err := utils.ParseDateStringAsTime(*obj.BirthDate) if err != nil { return nil, nil } end := time.Now() if obj.DeathDate != nil { deathdate, err := utils.ParseDateStringAsTime(*obj.DeathDate) if err == nil { end = deathdate } } birthYear := birthdate.Year() thisYear := end.Year() age := thisYear - birthYear if end.YearDay() < birthdate.YearDay() { age-- } return &age, nil } func (r *performerResolver) Measurements(ctx context.Context, obj *models.Performer) (*models.Measurements, error) { ret := models.Measurements{ BandSize: obj.BandSize, CupSize: obj.CupSize, Hip: obj.HipSize, Waist: obj.WaistSize, } return &ret, nil } func (r *performerResolver) Tattoos(ctx context.Context, obj *models.Performer) ([]models.BodyModification, error) { return dataloader.For(ctx).PerformerTattoosByID.Load(obj.ID) } func (r *performerResolver) Piercings(ctx context.Context, obj *models.Performer) ([]models.BodyModification, error) { return dataloader.For(ctx).PerformerPiercingsByID.Load(obj.ID) } func (r *performerResolver) Images(ctx context.Context, obj *models.Performer) ([]models.Image, error) { imageIDs, err := dataloader.For(ctx).PerformerImageIDsByID.Load(obj.ID) if err != nil { return nil, err } images, err := imageList(ctx, imageIDs) image.OrderPortrait(images) return images, err } func (r *performerResolver) Edits(ctx context.Context, obj *models.Performer) ([]models.Edit, error) { return r.services.Edit().FindByPerformerID(ctx, obj.ID) } func (r *performerResolver) SceneCount(ctx context.Context, obj *models.Performer) (int, error) { return r.services.Scene().CountByPerformer(ctx, obj.ID) } func (r *performerResolver) Scenes(ctx context.Context, obj *models.Performer, input *models.PerformerScenesInput) ([]models.Scene, error) { performers := []uuid.UUID{ obj.ID, } if input != nil && input.PerformedWith != nil { performers = append(performers, *input.PerformedWith) } var studios *models.MultiIDCriterionInput if input != nil && input.StudioID != nil { studios = &models.MultiIDCriterionInput{ Modifier: models.CriterionModifierIncludes, Value: []uuid.UUID{*input.StudioID}, } } var tags *models.MultiIDCriterionInput if input != nil { tags = input.Tags } filter := models.SceneQueryInput{ Performers: &models.MultiIDCriterionInput{ Modifier: models.CriterionModifierIncludesAll, Value: performers, }, Studios: studios, Tags: tags, Sort: "DATE", Direction: "DESC", Page: 1, PerPage: 10, } return r.services.Scene().Query(ctx, filter) } func (r *performerResolver) MergedIds(ctx context.Context, obj *models.Performer) ([]uuid.UUID, error) { return dataloader.For(ctx).PerformerMergeIDsBySourceID.Load(obj.ID) } func (r *performerResolver) MergedIntoID(ctx context.Context, obj *models.Performer) (*uuid.UUID, error) { res, err := dataloader.For(ctx).PerformerMergeIDsByID.Load(obj.ID) if len(res) == 1 { return &res[0], err } else if err != nil && len(res) > 1 { return nil, fmt.Errorf("invalid number of results returned, expecting exactly 1, found %d", len(res)) } return nil, err } func (r *performerResolver) Studios(ctx context.Context, obj *models.Performer, studioID *uuid.UUID) ([]models.PerformerStudio, error) { return r.services.Studio().CountByPerformer(ctx, obj.ID, studioID) } func (r *performerResolver) IsFavorite(ctx context.Context, obj *models.Performer) (bool, error) { return dataloader.For(ctx).PerformerIsFavoriteByID.Load(obj.ID) } ================================================ FILE: internal/api/resolver_model_performer_draft.go ================================================ package api import ( "context" "github.com/stashapp/stash-box/internal/models" ) type performerDraftResolver struct{ *Resolver } func (r *performerDraftResolver) ID(ctx context.Context, obj *models.PerformerDraft) (*string, error) { if obj.ID != nil { val := obj.ID.String() return &val, nil } return nil, nil } func (r *performerDraftResolver) Image(ctx context.Context, obj *models.PerformerDraft) (*models.Image, error) { if obj.Image == nil { return nil, nil } return r.services.Image().Find(ctx, *obj.Image) } ================================================ FILE: internal/api/resolver_model_performer_edit.go ================================================ package api import ( "context" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/pkg/utils" ) type performerEditResolver struct{ *Resolver } func (r *performerEditResolver) Gender(ctx context.Context, obj *models.PerformerEdit) (*models.GenderEnum, error) { var ret models.GenderEnum if obj.Gender == nil || !utils.ResolveEnumString(*obj.Gender, &ret) { return nil, nil } return &ret, nil } func (r *performerEditResolver) HairColor(ctx context.Context, obj *models.PerformerEdit) (*models.HairColorEnum, error) { var ret models.HairColorEnum if obj.HairColor == nil || !utils.ResolveEnumString(*obj.HairColor, &ret) { return nil, nil } return &ret, nil } func (r *performerEditResolver) EyeColor(ctx context.Context, obj *models.PerformerEdit) (*models.EyeColorEnum, error) { var ret models.EyeColorEnum if obj.EyeColor == nil || !utils.ResolveEnumString(*obj.EyeColor, &ret) { return nil, nil } return &ret, nil } func (r *performerEditResolver) Ethnicity(ctx context.Context, obj *models.PerformerEdit) (*models.EthnicityEnum, error) { var ret models.EthnicityEnum if obj.Ethnicity == nil || !utils.ResolveEnumString(*obj.Ethnicity, &ret) { return nil, nil } return &ret, nil } func (r *performerEditResolver) BreastType(ctx context.Context, obj *models.PerformerEdit) (*models.BreastTypeEnum, error) { var ret models.BreastTypeEnum if obj.BreastType == nil || !utils.ResolveEnumString(*obj.BreastType, &ret) { return nil, nil } return &ret, nil } func (r *performerEditResolver) AddedImages(ctx context.Context, obj *models.PerformerEdit) ([]models.Image, error) { return imageList(ctx, obj.AddedImages) } func (r *performerEditResolver) RemovedImages(ctx context.Context, obj *models.PerformerEdit) ([]models.Image, error) { return imageList(ctx, obj.RemovedImages) } func (r *performerEditResolver) Images(ctx context.Context, obj *models.PerformerEdit) ([]models.Image, error) { return r.services.Edit().GetMergedImages(ctx, obj.EditID) } func (r *performerEditResolver) Urls(ctx context.Context, obj *models.PerformerEdit) ([]models.URL, error) { return r.services.Edit().GetMergedURLs(ctx, obj.EditID) } func (r *performerEditResolver) Aliases(ctx context.Context, obj *models.PerformerEdit) ([]string, error) { return r.services.Edit().GetMergedPerformerAliases(ctx, obj.EditID) } func (r *performerEditResolver) Tattoos(ctx context.Context, obj *models.PerformerEdit) ([]models.BodyModification, error) { return r.services.Edit().GetMergedPerformerTattoos(ctx, obj.EditID) } func (r *performerEditResolver) Piercings(ctx context.Context, obj *models.PerformerEdit) ([]models.BodyModification, error) { return r.services.Edit().GetMergedPerformerPiercings(ctx, obj.EditID) } ================================================ FILE: internal/api/resolver_model_scene.go ================================================ package api import ( "context" "time" "github.com/stashapp/stash-box/internal/dataloader" "github.com/stashapp/stash-box/internal/image" "github.com/stashapp/stash-box/internal/models" ) type sceneResolver struct{ *Resolver } func (r *sceneResolver) ID(ctx context.Context, obj *models.Scene) (string, error) { return obj.ID.String(), nil } // Deprecated: use `ReleaseDate` func (r *sceneResolver) Date(ctx context.Context, obj *models.Scene) (*string, error) { ret := resolveFuzzyDate(obj.Date) if ret != nil { return &ret.Date, nil } return nil, nil } func (r *sceneResolver) ReleaseDate(ctx context.Context, obj *models.Scene) (*string, error) { return obj.Date, nil } func (r *sceneResolver) Studio(ctx context.Context, obj *models.Scene) (*models.Studio, error) { if !obj.StudioID.Valid { return nil, nil } studio, err := dataloader.For(ctx).StudioByID.Load(obj.StudioID.UUID) if err != nil { return nil, err } return studio, nil } func (r *sceneResolver) Tags(ctx context.Context, obj *models.Scene) ([]models.Tag, error) { tagIDs, err := dataloader.For(ctx).SceneTagIDsByID.Load(obj.ID) if err != nil { return nil, err } return tagList(ctx, tagIDs) } func (r *sceneResolver) Images(ctx context.Context, obj *models.Scene) ([]models.Image, error) { imageIDs, err := dataloader.For(ctx).SceneImageIDsByID.Load(obj.ID) if err != nil { return nil, err } images, err := imageList(ctx, imageIDs) image.OrderLandscape(images) return images, err } func (r *sceneResolver) Performers(ctx context.Context, obj *models.Scene) ([]models.PerformerAppearance, error) { appearances, err := dataloader.For(ctx).SceneAppearancesByID.Load(obj.ID) if err != nil { return nil, err } var ret []models.PerformerAppearance for _, appearance := range appearances { performer, err := dataloader.For(ctx).PerformerByID.Load(appearance.PerformerID) if err != nil { return nil, err } retApp := models.PerformerAppearance{ Performer: performer, As: appearance.As, } ret = append(ret, retApp) } return ret, nil } func (r *sceneResolver) Fingerprints(ctx context.Context, obj *models.Scene, isSubmitted *bool) ([]models.Fingerprint, error) { if isSubmitted != nil && *isSubmitted { return dataloader.For(ctx).SubmittedSceneFingerprintsByID.Load(obj.ID) } return dataloader.For(ctx).SceneFingerprintsByID.Load(obj.ID) } func (r *sceneResolver) Urls(ctx context.Context, obj *models.Scene) ([]models.URL, error) { return dataloader.For(ctx).SceneUrlsByID.Load(obj.ID) } func (r *sceneResolver) Edits(ctx context.Context, obj *models.Scene) ([]models.Edit, error) { return r.services.Edit().FindBySceneID(ctx, obj.ID) } func (r *sceneResolver) Created(ctx context.Context, obj *models.Scene) (*time.Time, error) { return &obj.CreatedAt, nil } func (r *sceneResolver) Updated(ctx context.Context, obj *models.Scene) (*time.Time, error) { return &obj.UpdatedAt, nil } ================================================ FILE: internal/api/resolver_model_scene_draft.go ================================================ package api import ( "context" "github.com/stashapp/stash-box/internal/models" ) type sceneDraftResolver struct{ *Resolver } func (r *sceneDraftResolver) ID(ctx context.Context, obj *models.SceneDraft) (*string, error) { if obj.ID != nil { val := obj.ID.String() return &val, nil } return nil, nil } func (r *sceneDraftResolver) Image(ctx context.Context, obj *models.SceneDraft) (*models.Image, error) { if obj.Image == nil { return nil, nil } return r.services.Image().Find(ctx, *obj.Image) } func (r *sceneDraftResolver) Performers(ctx context.Context, obj *models.SceneDraft) ([]models.SceneDraftPerformer, error) { return r.services.Draft().FindPerformers(ctx, obj.Performers) } func (r *sceneDraftResolver) Tags(ctx context.Context, obj *models.SceneDraft) ([]models.SceneDraftTag, error) { return r.services.Draft().FindTags(ctx, obj.Tags) } func (r *sceneDraftResolver) Studio(ctx context.Context, obj *models.SceneDraft) (models.SceneDraftStudio, error) { return r.services.Draft().FindStudio(ctx, obj.Studio) } ================================================ FILE: internal/api/resolver_model_scene_edit.go ================================================ package api import ( "context" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/dataloader" "github.com/stashapp/stash-box/internal/models" ) type sceneEditResolver struct{ *Resolver } func (r *sceneEditResolver) Studio(ctx context.Context, obj *models.SceneEdit) (*models.Studio, error) { if obj.StudioID == nil { return nil, nil } return r.services.Studio().FindByID(ctx, *obj.StudioID) } func (r *sceneEditResolver) performerAppearanceList(ctx context.Context, performers []models.PerformerAppearanceInput) ([]models.PerformerAppearance, error) { if len(performers) == 0 { return nil, nil } var uuids []uuid.UUID for _, p := range performers { uuids = append(uuids, p.PerformerID) } loadedPerformers, errors := dataloader.For(ctx).PerformerByID.LoadAll(uuids) for _, err := range errors { if err != nil { return nil, err } } var ret []models.PerformerAppearance for i, p := range performers { rr := models.PerformerAppearance{ Performer: loadedPerformers[i], As: p.As, } ret = append(ret, rr) } return ret, nil } func (r *sceneEditResolver) AddedPerformers(ctx context.Context, obj *models.SceneEdit) ([]models.PerformerAppearance, error) { return r.performerAppearanceList(ctx, obj.AddedPerformers) } func (r *sceneEditResolver) RemovedPerformers(ctx context.Context, obj *models.SceneEdit) ([]models.PerformerAppearance, error) { return r.performerAppearanceList(ctx, obj.RemovedPerformers) } func (r *sceneEditResolver) AddedTags(ctx context.Context, obj *models.SceneEdit) ([]models.Tag, error) { return tagList(ctx, obj.AddedTags) } func (r *sceneEditResolver) RemovedTags(ctx context.Context, obj *models.SceneEdit) ([]models.Tag, error) { return tagList(ctx, obj.RemovedTags) } func (r *sceneEditResolver) AddedImages(ctx context.Context, obj *models.SceneEdit) ([]models.Image, error) { return imageList(ctx, obj.AddedImages) } func (r *sceneEditResolver) RemovedImages(ctx context.Context, obj *models.SceneEdit) ([]models.Image, error) { return imageList(ctx, obj.RemovedImages) } func (r *sceneEditResolver) fingerprintList(ctx context.Context, fingerprints []models.FingerprintInput) ([]models.Fingerprint, error) { var ret []models.Fingerprint for _, fp := range fingerprints { rr := models.Fingerprint{ Hash: fp.Hash, Algorithm: fp.Algorithm, Duration: fp.Duration, } ret = append(ret, rr) } return ret, nil } func (r *sceneEditResolver) AddedFingerprints(ctx context.Context, obj *models.SceneEdit) ([]models.Fingerprint, error) { return r.fingerprintList(ctx, obj.AddedFingerprints) } func (r *sceneEditResolver) RemovedFingerprints(ctx context.Context, obj *models.SceneEdit) ([]models.Fingerprint, error) { return r.fingerprintList(ctx, obj.RemovedFingerprints) } func (r *sceneEditResolver) Fingerprints(ctx context.Context, obj *models.SceneEdit) ([]models.Fingerprint, error) { var ret []models.Fingerprint for _, fp := range obj.AddedFingerprints { ret = append(ret, models.Fingerprint{ Hash: fp.Hash, Algorithm: fp.Algorithm, Duration: fp.Duration, Submissions: 0, UserSubmitted: true, }) } return ret, nil } func (r *sceneEditResolver) Images(ctx context.Context, obj *models.SceneEdit) ([]models.Image, error) { return r.services.Edit().GetMergedImages(ctx, obj.EditID) } func (r *sceneEditResolver) Tags(ctx context.Context, obj *models.SceneEdit) ([]models.Tag, error) { return r.services.Edit().GetMergedTags(ctx, obj.EditID) } func (r *sceneEditResolver) Performers(ctx context.Context, obj *models.SceneEdit) ([]models.PerformerAppearance, error) { return r.services.Edit().GetMergedPerformers(ctx, obj.EditID) } func (r *sceneEditResolver) Urls(ctx context.Context, obj *models.SceneEdit) ([]models.URL, error) { return r.services.Edit().GetMergedURLs(ctx, obj.EditID) } ================================================ FILE: internal/api/resolver_model_site.go ================================================ package api import ( "context" "time" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/pkg/utils" ) type siteResolver struct{ *Resolver } func (r *siteResolver) ValidTypes(ctx context.Context, obj *models.Site) ([]models.ValidSiteTypeEnum, error) { var ret []models.ValidSiteTypeEnum for _, validType := range obj.ValidTypes { var resolvedType models.ValidSiteTypeEnum if utils.ResolveEnumString(validType, &resolvedType) { ret = append(ret, resolvedType) } } return ret, nil } func (r *siteResolver) Created(ctx context.Context, obj *models.Site) (*time.Time, error) { return &obj.CreatedAt, nil } func (r *siteResolver) Updated(ctx context.Context, obj *models.Site) (*time.Time, error) { return &obj.UpdatedAt, nil } func (r *siteResolver) Icon(ctx context.Context, obj *models.Site) (string, error) { baseURL, _ := ctx.Value(BaseURLCtxKey).(string) return baseURL + "/images/site/" + obj.ID.String(), nil } ================================================ FILE: internal/api/resolver_model_studio.go ================================================ package api import ( "context" "sort" "time" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/dataloader" "github.com/stashapp/stash-box/internal/models" ) type studioResolver struct{ *Resolver } func (r *studioResolver) ID(ctx context.Context, obj *models.Studio) (string, error) { return obj.ID.String(), nil } func (r *studioResolver) Urls(ctx context.Context, obj *models.Studio) ([]models.URL, error) { return dataloader.For(ctx).StudioUrlsByID.Load(obj.ID) } func (r *studioResolver) Parent(ctx context.Context, obj *models.Studio) (*models.Studio, error) { if !obj.ParentStudioID.Valid { return nil, nil } return r.services.Studio().FindByID(ctx, obj.ParentStudioID.UUID) } func (r *studioResolver) ChildStudios(ctx context.Context, obj *models.Studio) ([]models.Studio, error) { return r.services.Studio().FindByParentID(ctx, obj.ID) } func (r *studioResolver) SubStudios(ctx context.Context, obj *models.Studio, input *models.StudioQueryInput) (*models.QueryStudiosResultType, error) { var filter models.StudioQueryInput if input != nil { filter = *input } filter.Parent = &models.IDCriterionInput{ Value: []uuid.UUID{obj.ID}, Modifier: models.CriterionModifierEquals, } return r.services.Studio().Query(ctx, filter) } func (r *studioResolver) Images(ctx context.Context, obj *models.Studio) ([]models.Image, error) { imageIDs, err := dataloader.For(ctx).StudioImageIDsByID.Load(obj.ID) if err != nil { return nil, err } return imageList(ctx, imageIDs) } func (r *studioResolver) IsFavorite(ctx context.Context, obj *models.Studio) (bool, error) { return dataloader.For(ctx).StudioIsFavoriteByID.Load(obj.ID) } func (r *studioResolver) Created(ctx context.Context, obj *models.Studio) (*time.Time, error) { return &obj.CreatedAt, nil } func (r *studioResolver) Updated(ctx context.Context, obj *models.Studio) (*time.Time, error) { return &obj.UpdatedAt, nil } func (r *studioResolver) Performers(ctx context.Context, obj *models.Studio, input models.PerformerQueryInput) (*models.PerformerQuery, error) { input.StudioID = &obj.ID return &models.PerformerQuery{ Filter: input, }, nil } func (r *studioResolver) Aliases(ctx context.Context, obj *models.Studio) ([]string, error) { aliases, err := dataloader.For(ctx).StudioAliasesByID.Load(obj.ID) if err != nil { return nil, err } sort.Strings(aliases) return aliases, nil } ================================================ FILE: internal/api/resolver_model_studio_edit.go ================================================ package api import ( "context" "github.com/stashapp/stash-box/internal/models" ) type studioEditResolver struct{ *Resolver } func (r *studioEditResolver) Parent(ctx context.Context, obj *models.StudioEdit) (*models.Studio, error) { if obj.ParentID == nil { return nil, nil } return r.services.Studio().FindByID(ctx, *obj.ParentID) } func (r *studioEditResolver) AddedImages(ctx context.Context, obj *models.StudioEdit) ([]models.Image, error) { return imageList(ctx, obj.AddedImages) } func (r *studioEditResolver) RemovedImages(ctx context.Context, obj *models.StudioEdit) ([]models.Image, error) { return imageList(ctx, obj.RemovedImages) } func (r *studioEditResolver) Images(ctx context.Context, obj *models.StudioEdit) ([]models.Image, error) { return r.services.Edit().GetMergedImages(ctx, obj.EditID) } func (r *studioEditResolver) Urls(ctx context.Context, obj *models.StudioEdit) ([]models.URL, error) { return r.services.Edit().GetMergedURLs(ctx, obj.EditID) } ================================================ FILE: internal/api/resolver_model_tag.go ================================================ package api import ( "context" "sort" "time" "github.com/stashapp/stash-box/internal/dataloader" "github.com/stashapp/stash-box/internal/models" ) type tagResolver struct{ *Resolver } func (r *tagResolver) ID(ctx context.Context, obj *models.Tag) (string, error) { return obj.ID.String(), nil } func (r *tagResolver) Description(ctx context.Context, obj *models.Tag) (*string, error) { return obj.Description, nil } func (r *tagResolver) Aliases(ctx context.Context, obj *models.Tag) ([]string, error) { aliases, err := r.services.Tag().GetAliases(ctx, obj.ID) if err != nil { return nil, err } sort.Strings(aliases) return aliases, nil } func (r *tagResolver) Edits(ctx context.Context, obj *models.Tag) ([]models.Edit, error) { return r.services.Edit().FindByTagID(ctx, obj.ID) } func (r *tagResolver) Category(ctx context.Context, obj *models.Tag) (*models.TagCategory, error) { if obj.CategoryID.Valid { return dataloader.For(ctx).TagCategoryByID.Load(obj.CategoryID.UUID) } return nil, nil } func (r *tagResolver) Created(ctx context.Context, obj *models.Tag) (*time.Time, error) { return &obj.Created, nil } func (r *tagResolver) Updated(ctx context.Context, obj *models.Tag) (*time.Time, error) { return &obj.Updated, nil } ================================================ FILE: internal/api/resolver_model_tag_category.go ================================================ package api import ( "context" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/pkg/utils" ) type tagCategoryResolver struct{ *Resolver } func (r *tagCategoryResolver) ID(ctx context.Context, obj *models.TagCategory) (string, error) { return obj.ID.String(), nil } func (r *tagCategoryResolver) Name(ctx context.Context, obj *models.TagCategory) (string, error) { return obj.Name, nil } func (r *tagCategoryResolver) Group(ctx context.Context, obj *models.TagCategory) (models.TagGroupEnum, error) { var ret models.TagGroupEnum if !utils.ResolveEnumString(obj.Group, &ret) { return "", nil } return ret, nil } ================================================ FILE: internal/api/resolver_model_tag_edit.go ================================================ package api import ( "context" "github.com/stashapp/stash-box/internal/models" ) type tagEditResolver struct{ *Resolver } func (r *tagEditResolver) Category(ctx context.Context, obj *models.TagEdit) (*models.TagCategory, error) { if obj.CategoryID == nil { return nil, nil } return r.services.Tag().FindCategory(ctx, *obj.CategoryID) } func (r *tagEditResolver) Aliases(ctx context.Context, obj *models.TagEdit) ([]string, error) { return r.services.Edit().GetMergedStudioAliases(ctx, obj.EditID) } ================================================ FILE: internal/api/resolver_model_url.go ================================================ package api import ( "context" "strings" "github.com/stashapp/stash-box/internal/dataloader" "github.com/stashapp/stash-box/internal/models" ) type urlResolver struct{ *Resolver } func (r *urlResolver) URL(ctx context.Context, obj *models.URL) (string, error) { return obj.URL, nil } func (r *urlResolver) Site(ctx context.Context, obj *models.URL) (*models.Site, error) { return dataloader.For(ctx).SiteByID.Load(obj.SiteID) } func (r *urlResolver) Type(ctx context.Context, obj *models.URL) (string, error) { site, err := dataloader.For(ctx).SiteByID.Load(obj.SiteID) if err != nil { return "", err } return strings.ToUpper(site.Name), err } ================================================ FILE: internal/api/resolver_model_user.go ================================================ package api import ( "context" "github.com/stashapp/stash-box/internal/auth" "github.com/stashapp/stash-box/internal/models" ) type userResolver struct{ *Resolver } func (r *userResolver) ID(ctx context.Context, user *models.User) (string, error) { return user.ID.String(), nil } func (r *userResolver) Roles(ctx context.Context, user *models.User) ([]models.RoleEnum, error) { // Limit user role visibility to admins and user themself if err := auth.ValidateOwner(ctx, user.ID); err != nil { if err := auth.ValidateRole(ctx, models.RoleEnumAdmin); err != nil { return nil, nil } } return r.services.User().GetRoles(ctx, user.ID) } func (r *userResolver) VoteCount(ctx context.Context, obj *models.User) (*models.UserVoteCount, error) { return r.services.User().CountVotesByType(ctx, obj.ID) } func (r *userResolver) EditCount(ctx context.Context, obj *models.User) (*models.UserEditCount, error) { return r.services.User().CountEditsByStatus(ctx, obj.ID) } func (r *userResolver) InvitedBy(ctx context.Context, user *models.User) (*models.User, error) { if !user.InvitedByID.Valid { return nil, nil } return r.services.User().FindByID(ctx, user.InvitedByID.UUID) } func (r *userResolver) ActiveInviteCodes(ctx context.Context, user *models.User) ([]string, error) { // only show if current user or invite manager currentUser := auth.GetCurrentUser(ctx) if currentUser.ID != user.ID { if err := auth.ValidateRole(ctx, models.RoleEnumManageInvites); err != nil { return nil, nil } } codes, err := r.InviteCodes(ctx, user) if err != nil { return nil, err } var inviteCodes []string for _, code := range codes { inviteCodes = append(inviteCodes, code.ID.String()) } return inviteCodes, err } func (r *userResolver) InviteCodes(ctx context.Context, user *models.User) ([]models.InviteKey, error) { // only show if current user or invite manager currentUser := auth.GetCurrentUser(ctx) if currentUser.ID != user.ID { if err := auth.ValidateRole(ctx, models.RoleEnumManageInvites); err != nil { return nil, nil } } return r.services.UserToken().FindActiveInviteKeysForUser(ctx, user.ID) } func (r *userResolver) NotificationSubscriptions(ctx context.Context, user *models.User) ([]models.NotificationEnum, error) { return r.services.User().GetNotificationSubscriptions(ctx, user.ID) } ================================================ FILE: internal/api/resolver_mutation_draft.go ================================================ package api import ( "context" "github.com/99designs/gqlgen/graphql" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/auth" "github.com/stashapp/stash-box/internal/models" ) func (r *mutationResolver) SubmitSceneDraft(ctx context.Context, input models.SceneDraftInput) (*models.DraftSubmissionStatus, error) { input.Fingerprints = filterMD5FingerprintInputs(input.Fingerprints) imageID, err := r.createImage(ctx, input.Image) if err != nil { return nil, err } return r.services.Draft().SubmitScene(ctx, input, imageID) } func (r *mutationResolver) SubmitPerformerDraft(ctx context.Context, input models.PerformerDraftInput) (*models.DraftSubmissionStatus, error) { imageID, err := r.createImage(ctx, input.Image) if err != nil { return nil, err } return r.services.Draft().SubmitPerformer(ctx, input, imageID) } func (r *mutationResolver) DestroyDraft(ctx context.Context, id uuid.UUID) (bool, error) { return r.services.Draft().Destroy(ctx, auth.GetCurrentUser(ctx), id) } func (r *mutationResolver) createImage(ctx context.Context, file *graphql.Upload) (*uuid.UUID, error) { var imageID *uuid.UUID if file != nil { image, err := r.services.Image().Create(ctx, models.ImageCreateInput{ File: file, }) if err != nil { return nil, err } if image != nil { imageID = &image.ID } } return imageID, nil } ================================================ FILE: internal/api/resolver_mutation_edit.go ================================================ package api import ( "context" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" ) func (r *mutationResolver) SceneEdit(ctx context.Context, input models.SceneEditInput) (*models.Edit, error) { if input.Details != nil { input.Details.Fingerprints = filterMD5FingerprintInputs(input.Details.Fingerprints) } edit, err := r.services.Edit().CreateSceneEdit(ctx, input) if err == nil { go r.services.Notification().OnCreateEdit(context.Background(), edit) } return edit, err } func (r *mutationResolver) SceneEditUpdate(ctx context.Context, id uuid.UUID, input models.SceneEditInput) (*models.Edit, error) { if input.Details != nil { input.Details.Fingerprints = filterMD5FingerprintInputs(input.Details.Fingerprints) } edit, err := r.services.Edit().UpdateSceneEdit(ctx, id, input) if err == nil { go r.services.Notification().OnUpdateEdit(context.Background(), edit) } return edit, err } func (r *mutationResolver) StudioEdit(ctx context.Context, input models.StudioEditInput) (*models.Edit, error) { edit, err := r.services.Edit().CreateStudioEdit(ctx, input) if err == nil { go r.services.Notification().OnCreateEdit(context.Background(), edit) } return edit, err } func (r *mutationResolver) StudioEditUpdate(ctx context.Context, id uuid.UUID, input models.StudioEditInput) (*models.Edit, error) { edit, err := r.services.Edit().UpdateStudioEdit(ctx, id, input) if err == nil { go r.services.Notification().OnUpdateEdit(context.Background(), edit) } return edit, err } func (r *mutationResolver) TagEdit(ctx context.Context, input models.TagEditInput) (*models.Edit, error) { edit, err := r.services.Edit().CreateTagEdit(ctx, input) if err == nil { go r.services.Notification().OnCreateEdit(context.Background(), edit) } return edit, err } func (r *mutationResolver) TagEditUpdate(ctx context.Context, id uuid.UUID, input models.TagEditInput) (*models.Edit, error) { edit, err := r.services.Edit().UpdateTagEdit(ctx, id, input) if err == nil { go r.services.Notification().OnUpdateEdit(context.Background(), edit) } return edit, err } func (r *mutationResolver) PerformerEdit(ctx context.Context, input models.PerformerEditInput) (*models.Edit, error) { edit, err := r.services.Edit().CreatePerformerEdit(ctx, input) if err == nil { go r.services.Notification().OnCreateEdit(context.Background(), edit) } return edit, err } func (r *mutationResolver) PerformerEditUpdate(ctx context.Context, id uuid.UUID, input models.PerformerEditInput) (*models.Edit, error) { edit, err := r.services.Edit().UpdatePerformerEdit(ctx, id, input) if err == nil { go r.services.Notification().OnUpdateEdit(context.Background(), edit) } return edit, err } func (r *mutationResolver) EditVote(ctx context.Context, input models.EditVoteInput) (*models.Edit, error) { edit, err := r.services.Edit().CreateVote(ctx, input) if err == nil { if input.Vote == models.VoteTypeEnumReject { go r.services.Notification().OnEditDownvote(context.Background(), edit) } // Check if the edit was closed due to reaching the voting threshold if edit.Status != models.VoteStatusEnumPending.String() { go r.services.Notification().OnApplyEdit(context.Background(), edit) } } return edit, err } func (r *mutationResolver) EditComment(ctx context.Context, input models.EditCommentInput) (*models.Edit, error) { edit, comment, err := r.services.Edit().CreateComment(ctx, input) if err == nil { go r.services.Notification().OnEditComment(context.Background(), comment) } return edit, err } func (r *mutationResolver) CancelEdit(ctx context.Context, input models.CancelEditInput) (*models.Edit, error) { edit, err := r.services.Edit().Cancel(ctx, input) if err == nil { go r.services.Notification().OnCancelEdit(context.Background(), edit) } return edit, err } func (r *mutationResolver) ApplyEdit(ctx context.Context, input models.ApplyEditInput) (*models.Edit, error) { edit, err := r.services.Edit().Apply(ctx, input) if err == nil { go r.services.Notification().OnApplyEdit(context.Background(), edit) } return edit, err } func (r *mutationResolver) DeleteEdit(ctx context.Context, input models.DeleteEditInput) (bool, error) { err := r.services.Edit().DeleteWithAudit(ctx, input) return err == nil, err } func (r *mutationResolver) AmendEdit(ctx context.Context, input models.AmendEditInput) (*models.Edit, error) { return r.services.Edit().AmendEdit(ctx, input) } ================================================ FILE: internal/api/resolver_mutation_image.go ================================================ package api import ( "context" "github.com/stashapp/stash-box/internal/models" ) func (r *mutationResolver) ImageCreate(ctx context.Context, input models.ImageCreateInput) (*models.Image, error) { return r.services.Image().Create(ctx, input) } func (r *mutationResolver) ImageDestroy(ctx context.Context, input models.ImageDestroyInput) (bool, error) { err := r.services.Image().Destroy(ctx, input.ID) if err != nil { return false, err } return true, nil } ================================================ FILE: internal/api/resolver_mutation_notifications.go ================================================ package api import ( "context" "github.com/stashapp/stash-box/internal/auth" "github.com/stashapp/stash-box/internal/models" ) func (r *mutationResolver) MarkNotificationsRead(ctx context.Context, notification *models.MarkNotificationReadInput) (bool, error) { user := auth.GetCurrentUser(ctx) if notification == nil { err := r.services.Notification().MarkAllRead(ctx, user.ID) return err == nil, err } err := r.services.Notification().MarkRead(ctx, user.ID, notification.Type, notification.ID) return err == nil, err } func (r *mutationResolver) UpdateNotificationSubscriptions(ctx context.Context, subscriptions []models.NotificationEnum) (bool, error) { user := auth.GetCurrentUser(ctx) if auth.IsRole(ctx, models.RoleEnumEdit) { err := r.services.Notification().UpdateNotificationSubscriptions(ctx, user.ID, subscriptions) return err == nil, err } isFavoriteSubscription := map[models.NotificationEnum]bool{ models.NotificationEnumFavoritePerformerScene: true, models.NotificationEnumFavoritePerformerEdit: true, models.NotificationEnumFavoriteStudioScene: true, models.NotificationEnumFavoriteStudioEdit: true, } var filteredSubscriptions []models.NotificationEnum for _, s := range subscriptions { if isFavoriteSubscription[s] { filteredSubscriptions = append(filteredSubscriptions, s) } } err := r.services.Notification().UpdateNotificationSubscriptions(ctx, user.ID, filteredSubscriptions) return err == nil, err } ================================================ FILE: internal/api/resolver_mutation_performer.go ================================================ package api import ( "context" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/auth" "github.com/stashapp/stash-box/internal/models" ) func (r *mutationResolver) PerformerCreate(ctx context.Context, input models.PerformerCreateInput) (*models.Performer, error) { return r.services.Performer().Create(ctx, input) } func (r *mutationResolver) PerformerUpdate(ctx context.Context, input models.PerformerUpdateInput) (*models.Performer, error) { return r.services.Performer().Update(ctx, input) } func (r *mutationResolver) PerformerDestroy(ctx context.Context, input models.PerformerDestroyInput) (bool, error) { err := r.services.Performer().Delete(ctx, input.ID) if err != nil { return false, err } return true, nil } func (r *mutationResolver) FavoritePerformer(ctx context.Context, id uuid.UUID, favorite bool) (bool, error) { user := auth.GetCurrentUser(ctx) err := r.services.Performer().Favorite(ctx, user.ID, id, favorite) return err == nil, err } ================================================ FILE: internal/api/resolver_mutation_scene.go ================================================ package api import ( "context" "errors" "github.com/stashapp/stash-box/internal/models" ) func (r *mutationResolver) SceneCreate(ctx context.Context, input models.SceneCreateInput) (*models.Scene, error) { input.Fingerprints = filterMD5FingerprintEditInputs(input.Fingerprints) s := r.services.Scene() return s.Create(ctx, input) } func (r *mutationResolver) SceneUpdate(ctx context.Context, input models.SceneUpdateInput) (*models.Scene, error) { input.Fingerprints = filterMD5FingerprintEditInputs(input.Fingerprints) s := r.services.Scene() return s.Update(ctx, input) } func (r *mutationResolver) SceneDestroy(ctx context.Context, input models.SceneDestroyInput) (bool, error) { s := r.services.Scene() err := s.Delete(ctx, input.ID) return err == nil, err } func (r *mutationResolver) SubmitFingerprint(ctx context.Context, input models.FingerprintSubmission) (bool, error) { // Filter out MD5 fingerprints if input.Fingerprint != nil && input.Fingerprint.Algorithm == models.FingerprintAlgorithmMd5 { return true, nil } s := r.services.Scene() return s.SubmitFingerprint(ctx, input) } func (r *mutationResolver) SubmitFingerprints(ctx context.Context, input []models.FingerprintBatchSubmission) ([]models.FingerprintSubmissionResult, error) { // Validate max 1000 fingerprints if len(input) > 1000 { return nil, errors.New("maximum of 1000 fingerprints allowed per batch") } s := r.services.Scene() return s.SubmitFingerprints(ctx, input) } func (r *mutationResolver) SceneMoveFingerprintSubmissions(ctx context.Context, input models.MoveFingerprintSubmissionsInput) (bool, error) { s := r.services.Scene() err := s.MoveFingerprintSubmissions(ctx, input) return err == nil, err } func (r *mutationResolver) SceneDeleteFingerprintSubmissions(ctx context.Context, input models.DeleteFingerprintSubmissionsInput) (bool, error) { s := r.services.Scene() err := s.DeleteFingerprintSubmissions(ctx, input) return err == nil, err } ================================================ FILE: internal/api/resolver_mutation_site.go ================================================ package api import ( "context" "github.com/stashapp/stash-box/internal/models" ) func (r *mutationResolver) SiteCreate(ctx context.Context, input models.SiteCreateInput) (*models.Site, error) { return r.services.Site().Create(ctx, input) } func (r *mutationResolver) SiteUpdate(ctx context.Context, input models.SiteUpdateInput) (*models.Site, error) { return r.services.Site().Update(ctx, input) } func (r *mutationResolver) SiteDestroy(ctx context.Context, input models.SiteDestroyInput) (bool, error) { err := r.services.Site().Destroy(ctx, input.ID) return err == nil, err } ================================================ FILE: internal/api/resolver_mutation_studio.go ================================================ package api import ( "context" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" ) func (r *mutationResolver) StudioCreate(ctx context.Context, input models.StudioCreateInput) (*models.Studio, error) { return r.services.Studio().Create(ctx, input) } func (r *mutationResolver) StudioUpdate(ctx context.Context, input models.StudioUpdateInput) (*models.Studio, error) { return r.services.Studio().Update(ctx, input) } func (r *mutationResolver) StudioDestroy(ctx context.Context, input models.StudioDestroyInput) (bool, error) { err := r.services.Studio().Delete(ctx, input.ID) return err == nil, err } func (r *mutationResolver) FavoriteStudio(ctx context.Context, id uuid.UUID, favorite bool) (bool, error) { err := r.services.Studio().Favorite(ctx, id, favorite) return err == nil, err } ================================================ FILE: internal/api/resolver_mutation_tag.go ================================================ package api import ( "context" "github.com/stashapp/stash-box/internal/models" ) func (r *mutationResolver) TagCreate(ctx context.Context, input models.TagCreateInput) (*models.Tag, error) { return r.services.Tag().Create(ctx, input) } func (r *mutationResolver) TagUpdate(ctx context.Context, input models.TagUpdateInput) (*models.Tag, error) { return r.services.Tag().Update(ctx, input) } func (r *mutationResolver) TagDestroy(ctx context.Context, input models.TagDestroyInput) (bool, error) { err := r.services.Tag().Delete(ctx, input) return err == nil, err } ================================================ FILE: internal/api/resolver_mutation_tag_category.go ================================================ package api import ( "context" "github.com/stashapp/stash-box/internal/models" ) func (r *mutationResolver) TagCategoryCreate(ctx context.Context, input models.TagCategoryCreateInput) (*models.TagCategory, error) { return r.services.Tag().CreateCategory(ctx, input) } func (r *mutationResolver) TagCategoryUpdate(ctx context.Context, input models.TagCategoryUpdateInput) (*models.TagCategory, error) { return r.services.Tag().UpdateCategory(ctx, input) } func (r *mutationResolver) TagCategoryDestroy(ctx context.Context, input models.TagCategoryDestroyInput) (bool, error) { err := r.services.Tag().DeleteCategory(ctx, input) return err == nil, err } ================================================ FILE: internal/api/resolver_mutation_user.go ================================================ package api import ( "context" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" ) func (r *mutationResolver) UserCreate(ctx context.Context, input models.UserCreateInput) (*models.User, error) { return r.services.User().Create(ctx, input) } func (r *mutationResolver) UserUpdate(ctx context.Context, input models.UserUpdateInput) (*models.User, error) { return r.services.User().Update(ctx, input) } func (r *mutationResolver) UserDestroy(ctx context.Context, input models.UserDestroyInput) (bool, error) { err := r.services.User().Delete(ctx, input) return err == nil, err } func (r *mutationResolver) RegenerateAPIKey(ctx context.Context, userID *uuid.UUID) (string, error) { return r.services.User().RegenerateAPIKey(ctx, userID) } func (r *mutationResolver) ResetPassword(ctx context.Context, input models.ResetPasswordInput) (bool, error) { err := r.services.User().ResetPassword(ctx, input) return err == nil, err } func (r *mutationResolver) ChangePassword(ctx context.Context, input models.UserChangePasswordInput) (bool, error) { err := r.services.User().ChangePassword(ctx, input) return err == nil, err } func (r *mutationResolver) NewUser(ctx context.Context, input models.NewUserInput) (*uuid.UUID, error) { return r.services.User().NewUser(ctx, input.Email, input.InviteKey) } func (r *mutationResolver) ActivateNewUser(ctx context.Context, input models.ActivateNewUserInput) (*models.User, error) { return r.services.User().ActivateNewUser(ctx, input) } func (r *mutationResolver) GenerateInviteCodes(ctx context.Context, input *models.GenerateInviteCodeInput) ([]uuid.UUID, error) { return r.services.User().GenerateInviteCodes(ctx, input) } func (r *mutationResolver) GenerateInviteCode(ctx context.Context) (*uuid.UUID, error) { return r.services.User().GenerateInviteCode(ctx) } func (r *mutationResolver) RescindInviteCode(ctx context.Context, inviteKeyID uuid.UUID) (bool, error) { err := r.services.User().RescindInviteCode(ctx, inviteKeyID) return err == nil, err } func (r *mutationResolver) GrantInvite(ctx context.Context, input models.GrantInviteInput) (int, error) { return r.services.User().GrantInvite(ctx, input) } func (r *mutationResolver) RevokeInvite(ctx context.Context, input models.RevokeInviteInput) (int, error) { return r.services.User().RevokeInvite(ctx, input) } func (r *mutationResolver) RequestChangeEmail(ctx context.Context) (models.UserChangeEmailStatus, error) { return r.services.User().RequestChangeEmail(ctx) } func (r *mutationResolver) ValidateChangeEmail(ctx context.Context, tokenID uuid.UUID, email string) (models.UserChangeEmailStatus, error) { return r.services.User().ValidateChangeEmail(ctx, tokenID, email) } func (r *mutationResolver) ConfirmChangeEmail(ctx context.Context, tokenID uuid.UUID) (models.UserChangeEmailStatus, error) { return r.services.User().ConfirmChangeEmail(ctx, tokenID) } ================================================ FILE: internal/api/resolver_query_draft.go ================================================ package api import ( "context" "fmt" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/auth" "github.com/stashapp/stash-box/internal/models" ) func (r *queryResolver) FindDrafts(ctx context.Context) ([]models.Draft, error) { user := auth.GetCurrentUser(ctx) return r.services.Draft().FindByUser(ctx, user.ID) } func (r *queryResolver) FindDraft(ctx context.Context, id uuid.UUID) (*models.Draft, error) { draft, err := r.services.Draft().FindByID(ctx, id) if err != nil { return nil, err } user := auth.GetCurrentUser(ctx) if user.ID != draft.UserID { return nil, fmt.Errorf("draft not found: %s", id) } return draft, nil } ================================================ FILE: internal/api/resolver_query_edit.go ================================================ package api import ( "context" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" ) func (r *queryResolver) FindEdit(ctx context.Context, id uuid.UUID) (*models.Edit, error) { return r.services.Edit().FindByID(ctx, id) } func (r *queryResolver) QueryEdits(ctx context.Context, input models.EditQueryInput) (*models.EditQuery, error) { return &models.EditQuery{ Filter: input, }, nil } type queryEditResolver struct{ *Resolver } func (r *queryEditResolver) Count(ctx context.Context, obj *models.EditQuery) (int, error) { return r.services.Edit().QueryCount(ctx, obj.Filter) } func (r *queryEditResolver) Edits(ctx context.Context, obj *models.EditQuery) ([]models.Edit, error) { return r.services.Edit().QueryEdits(ctx, obj.Filter) } ================================================ FILE: internal/api/resolver_query_mod_audit.go ================================================ package api import ( "context" "github.com/stashapp/stash-box/internal/models" ) func (r *queryResolver) QueryModAudits(ctx context.Context, input models.ModAuditQueryInput) (*models.ModAuditQuery, error) { return &models.ModAuditQuery{ Filter: input, }, nil } type queryModAuditResolver struct{ *Resolver } func (r *queryModAuditResolver) Count(ctx context.Context, obj *models.ModAuditQuery) (int, error) { return r.services.ModAudit().GetModAuditCount(ctx, obj.Filter) } func (r *queryModAuditResolver) Audits(ctx context.Context, obj *models.ModAuditQuery) ([]models.ModAudit, error) { return r.services.ModAudit().QueryModAudits(ctx, obj.Filter) } type modAuditResolver struct{ *Resolver } func (r *modAuditResolver) Action(ctx context.Context, obj *models.ModAudit) (models.ModAuditActionEnum, error) { return models.ModAuditActionEnum(obj.Action), nil } func (r *modAuditResolver) User(ctx context.Context, obj *models.ModAudit) (*models.User, error) { if !obj.UserID.Valid { return nil, nil } return r.services.User().FindByID(ctx, obj.UserID.UUID) } ================================================ FILE: internal/api/resolver_query_notifications.go ================================================ package api import ( "context" "github.com/stashapp/stash-box/internal/auth" "github.com/stashapp/stash-box/internal/models" ) func (r *queryResolver) QueryNotifications(ctx context.Context, input models.QueryNotificationsInput) (*models.QueryNotificationsResult, error) { return &models.QueryNotificationsResult{ Input: input, }, nil } type queryNotificationsResolver struct{ *Resolver } func (r *queryNotificationsResolver) Count(ctx context.Context, query *models.QueryNotificationsResult) (int, error) { currentUser := auth.GetCurrentUser(ctx) unreadOnly := query.Input.UnreadOnly != nil && *query.Input.UnreadOnly return r.services.Notification().GetNotificationsCount(ctx, currentUser.ID, unreadOnly, query.Input.Type) } func (r *queryNotificationsResolver) Notifications(ctx context.Context, query *models.QueryNotificationsResult) ([]models.Notification, error) { currentUser := auth.GetCurrentUser(ctx) unreadOnly := query.Input.UnreadOnly != nil && *query.Input.UnreadOnly page := query.Input.Page perPage := query.Input.PerPage return r.services.Notification().GetNotifications(ctx, currentUser.ID, unreadOnly, page, perPage, query.Input.Type) } func (r *queryResolver) GetUnreadNotificationCount(ctx context.Context) (int, error) { currentUser := auth.GetCurrentUser(ctx) return r.services.Notification().GetNotificationsCount(ctx, currentUser.ID, true, nil) } ================================================ FILE: internal/api/resolver_query_performer.go ================================================ package api import ( "context" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" ) func (r *queryResolver) FindPerformer(ctx context.Context, id uuid.UUID) (*models.Performer, error) { return r.services.Performer().FindByID(ctx, id) } func (r *queryResolver) QueryPerformers(ctx context.Context, input models.PerformerQueryInput) (*models.PerformerQuery, error) { return &models.PerformerQuery{ Filter: input, }, nil } type queryPerformerResolver struct{ *Resolver } func (r *queryPerformerResolver) Count(ctx context.Context, obj *models.PerformerQuery) (int, error) { if obj.SearchResults != nil { return obj.SearchResults.Count, nil } return r.services.Performer().QueryCount(ctx, obj.Filter) } func (r *queryPerformerResolver) Performers(ctx context.Context, obj *models.PerformerQuery) ([]models.Performer, error) { if obj.SearchResults != nil { return obj.SearchResults.Performers, nil } return r.services.Performer().Query(ctx, obj.Filter) } func (r *queryPerformerResolver) Facets(ctx context.Context, obj *models.PerformerQuery) (*models.PerformerSearchFacets, error) { if obj.SearchResults != nil { return obj.SearchResults.Facets, nil } return nil, nil } func (r *queryResolver) QueryExistingPerformer(ctx context.Context, input models.QueryExistingPerformerInput) (*models.QueryExistingPerformerResult, error) { return &models.QueryExistingPerformerResult{ Input: input, }, nil } type queryExistingPerformerResolver struct{ *Resolver } func (r *queryExistingPerformerResolver) Edits(ctx context.Context, obj *models.QueryExistingPerformerResult) ([]models.Edit, error) { return r.services.Edit().FindPendingPerformerCreation(ctx, obj.Input) } func (r *queryExistingPerformerResolver) Performers(ctx context.Context, obj *models.QueryExistingPerformerResult) ([]models.Performer, error) { return r.services.Performer().FindExistingPerformers(ctx, obj.Input) } // Deprecated: Use SearchPerformers instead func (r *queryResolver) SearchPerformer(ctx context.Context, term string, limit *int) ([]models.Performer, error) { result, err := r.services.Performer().SearchPerformer(ctx, term, limit, nil, nil, nil) if err != nil { return nil, err } if result.SearchResults != nil { return result.SearchResults.Performers, nil } return nil, nil } func (r *queryResolver) SearchPerformers(ctx context.Context, term string, limit *int, page *int, perPage *int, filter *models.PerformerSearchFilter) (*models.PerformerQuery, error) { return r.services.Performer().SearchPerformer(ctx, term, limit, page, perPage, filter) } ================================================ FILE: internal/api/resolver_query_scene.go ================================================ package api import ( "context" "errors" "strings" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" ) func (r *queryResolver) FindScene(ctx context.Context, id uuid.UUID) (*models.Scene, error) { return r.services.Scene().FindByID(ctx, id) } func (r *queryResolver) QueryScenes(ctx context.Context, input models.SceneQueryInput) (*models.SceneQuery, error) { return &models.SceneQuery{ Filter: input, }, nil } func (r *queryResolver) FindScenesBySceneFingerprints(ctx context.Context, sceneFingerprints [][]models.FingerprintQueryInput) ([][]*models.Scene, error) { if len(sceneFingerprints) > 40 { return nil, errors.New("too many scenes") } sceneFingerprints = filterMD5FingerprintQueryInputs(sceneFingerprints) return r.services.Scene().FindScenesBySceneFingerprints(ctx, sceneFingerprints) } type querySceneResolver struct{ *Resolver } func (r *querySceneResolver) Count(ctx context.Context, obj *models.SceneQuery) (int, error) { if obj.SearchResults != nil { return obj.SearchResults.Count, nil } return r.services.Scene().QueryCount(ctx, obj.Filter) } func (r *querySceneResolver) Scenes(ctx context.Context, obj *models.SceneQuery) ([]models.Scene, error) { if obj.SearchResults != nil { return obj.SearchResults.Scenes, nil } return r.services.Scene().Query(ctx, obj.Filter) } func (r *queryResolver) QueryExistingScene(ctx context.Context, input models.QueryExistingSceneInput) (*models.QueryExistingSceneResult, error) { input.Fingerprints = filterMD5FingerprintInputs(input.Fingerprints) return &models.QueryExistingSceneResult{ Input: input, }, nil } type queryExistingSceneResolver struct{ *Resolver } func (r *queryExistingSceneResolver) Edits(ctx context.Context, obj *models.QueryExistingSceneResult) ([]models.Edit, error) { return r.services.Edit().FindPendingSceneCreation(ctx, obj.Input) } func (r *queryExistingSceneResolver) Scenes(ctx context.Context, obj *models.QueryExistingSceneResult) ([]models.Scene, error) { return r.services.Scene().FindExistingScenes(ctx, obj.Input) } // Deprecated: Use SearchScenes instead func (r *queryResolver) SearchScene(ctx context.Context, term string, limit *int) ([]models.Scene, error) { result, err := r.searchScenes(ctx, term, limit, nil, nil) if err != nil { return nil, err } if result.SearchResults != nil { return result.SearchResults.Scenes, nil } return nil, nil } func (r *queryResolver) SearchScenes(ctx context.Context, term string, limit *int, page *int, perPage *int) (*models.SceneQuery, error) { return r.searchScenes(ctx, term, limit, page, perPage) } func (r *queryResolver) searchScenes(ctx context.Context, term string, limit *int, page *int, perPage *int) (*models.SceneQuery, error) { trimmedQuery := strings.TrimSpace(term) sceneID, err := uuid.FromString(trimmedQuery) if err == nil { var scenes []models.Scene scene, err := r.services.Scene().FindByID(ctx, sceneID) if scene != nil { scenes = append(scenes, *scene) } return &models.SceneQuery{ SearchResults: &models.SceneSearchResults{ Scenes: scenes, Count: len(scenes), }, }, err } searchLimit := 10 searchOffset := 0 if perPage != nil && *perPage > 0 { searchLimit = *perPage } else if limit != nil && *limit > 0 { searchLimit = *limit } if page != nil && *page > 1 { searchOffset = (*page - 1) * searchLimit } if strings.HasPrefix(trimmedQuery, "https://") || strings.HasPrefix(trimmedQuery, "http://") { scenes, err := r.services.Scene().FindByURL(ctx, trimmedQuery, searchLimit) return &models.SceneQuery{ SearchResults: &models.SceneSearchResults{ Scenes: scenes, Count: len(scenes), }, }, err } return r.services.Scene().SearchScenesWithCount(ctx, trimmedQuery, searchLimit, searchOffset) } ================================================ FILE: internal/api/resolver_query_site.go ================================================ package api import ( "context" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" ) func (r *queryResolver) FindSite(ctx context.Context, id uuid.UUID) (*models.Site, error) { return r.services.Site().GetByID(ctx, id) } func (r *queryResolver) QuerySites(ctx context.Context) (*models.QuerySitesResultType, error) { sites, count, err := r.services.Site().Query(ctx) if err != nil { return nil, err } return &models.QuerySitesResultType{ Sites: sites, Count: count, }, nil } ================================================ FILE: internal/api/resolver_query_studio.go ================================================ package api import ( "context" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" ) func (r *queryResolver) FindStudio(ctx context.Context, id *uuid.UUID, name *string) (*models.Studio, error) { if id != nil { return r.services.Studio().FindByID(ctx, *id) } else if name != nil { return r.services.Studio().FindByName(ctx, *name) } return nil, nil } func (r *queryResolver) QueryStudios(ctx context.Context, input models.StudioQueryInput) (*models.QueryStudiosResultType, error) { return r.services.Studio().Query(ctx, input) } func (r *queryResolver) SearchStudio(ctx context.Context, term string, limit *int) ([]models.Studio, error) { s := r.services.Studio() id := parseUUID(term) if !id.IsNil() { var studios []models.Studio studio, err := s.FindByID(ctx, id) if studio != nil { studios = append(studios, *studio) } return studios, err } searchLimit := 10 if limit != nil { searchLimit = *limit } return s.Search(ctx, term, searchLimit) } ================================================ FILE: internal/api/resolver_query_tag.go ================================================ package api import ( "context" "strings" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" ) func (r *queryResolver) FindTag(ctx context.Context, id *uuid.UUID, name *string) (*models.Tag, error) { s := r.services.Tag() if id != nil { return s.Find(ctx, *id) } else if name != nil { return s.FindByName(ctx, *name) } return nil, nil } func (r *queryResolver) FindTagOrAlias(ctx context.Context, name string) (*models.Tag, error) { return r.services.Tag().FindByNameOrAlias(ctx, name) } func (r *queryResolver) QueryTags(ctx context.Context, input models.TagQueryInput) (*models.QueryTagsResultType, error) { s := r.services.Tag() if input.Name != nil { tagID, err := uuid.FromString(*input.Name) if err == nil { tag, err := s.Find(ctx, tagID) if tag != nil { return &models.QueryTagsResultType{ Tags: []models.Tag{*tag}, Count: 1, }, err } } } return s.Query(ctx, input) } func (r *queryResolver) SearchTag(ctx context.Context, term string, limit *int) ([]models.Tag, error) { trimmedQuery := strings.TrimSpace(term) tagID, err := uuid.FromString(trimmedQuery) if err == nil { var tags []models.Tag tag, err := r.services.Tag().Find(ctx, tagID) if tag != nil { tags = append(tags, *tag) } return tags, err } searchLimit := 10 if limit != nil { searchLimit = *limit } return r.services.Tag().SearchTags(ctx, trimmedQuery, searchLimit) } ================================================ FILE: internal/api/resolver_query_tag_category.go ================================================ package api import ( "context" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" ) func (r *queryResolver) FindTagCategory(ctx context.Context, id uuid.UUID) (*models.TagCategory, error) { return r.services.Tag().FindCategory(ctx, id) } func (r *queryResolver) QueryTagCategories(ctx context.Context) (*models.QueryTagCategoriesResultType, error) { count, categories, err := r.services.Tag().QueryCategories(ctx) if err != nil { return nil, err } return &models.QueryTagCategoriesResultType{ TagCategories: categories, Count: count, }, nil } ================================================ FILE: internal/api/resolver_query_user.go ================================================ package api import ( "context" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/auth" "github.com/stashapp/stash-box/internal/models" ) func (r *queryResolver) FindUser(ctx context.Context, id *uuid.UUID, username *string) (*models.User, error) { var ret *models.User var err error if id != nil { ret, err = r.services.User().FindByID(ctx, *id) } else if username != nil { ret, err = r.services.User().FindByName(ctx, *username) } return ret, err } func (r *queryResolver) QueryUsers(ctx context.Context, input models.UserQueryInput) (*models.QueryUsersResultType, error) { return r.services.User().Query(ctx, input) } func (r *queryResolver) Me(ctx context.Context) (*models.User, error) { currentUser := auth.GetCurrentUser(ctx) if currentUser == nil { return nil, auth.ErrUnauthorized } return currentUser, nil } ================================================ FILE: internal/api/routes_image.go ================================================ package api import ( "errors" "io" "net/http" "os" "slices" "strconv" "time" "github.com/jackc/pgx/v5" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/internal/service" "github.com/stashapp/stash-box/internal/storage" "github.com/go-chi/chi/v5" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/config" "github.com/stashapp/stash-box/internal/image" "github.com/stashapp/stash-box/internal/image/cache" "github.com/stashapp/stash-box/pkg/logger" ) type imageRoutes struct { fac service.Factory } func (rs imageRoutes) Routes() chi.Router { r := chi.NewRouter() r.Get("/{uuid}", rs.image) r.Get("/site/{uuid}", rs.siteImage) return r } func (rs imageRoutes) image(w http.ResponseWriter, r *http.Request) { uuid, err := uuid.FromString(chi.URLParam(r, "uuid")) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } requestedSize, err := getImageSize(r) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) } cacheManager := cache.GetCacheManager() // Check for cached image if requestedSize != 0 && cacheManager != nil { reader, err := cacheManager.Read(uuid, requestedSize) if err == nil { defer reader.Close() w.Header().Add("Cache-Control", "max-age=604800000") // Use http.ServeContent for *os.File to enable sendfile syscall if file, ok := reader.(*os.File); ok { http.ServeContent(w, r, "", time.Time{}, file) return } if _, err := io.Copy(w, reader); err != nil { logger.Debugf("failed to read cached image: %v", err) w.Header().Set("Cache-Control", "no-store") http.Error(w, err.Error(), http.StatusInternalServerError) } return } } ctx := r.Context() imageService := rs.fac.Image() databaseImage, err := imageService.Find(ctx, uuid) if err != nil { if errors.Is(err, pgx.ErrNoRows) { http.NotFound(w, r) } else { http.Error(w, err.Error(), http.StatusInternalServerError) } return } if databaseImage == nil { http.NotFound(w, r) return } reader, size, err := imageService.Read(*databaseImage) if err != nil { http.Error(w, err.Error(), http.StatusNotFound) return } defer reader.Close() if databaseImage.Width == -1 { w.Header().Add("Content-Type", "image/svg+xml") w.Header().Add("Content-Security-Policy", "script-src 'none'") } w.Header().Add("Cache-Control", "max-age=604800000") // Resize image if shouldResize(databaseImage, requestedSize) { data, err := image.Resize(reader, requestedSize, databaseImage, size) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } if _, err := w.Write(data); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } if cacheManager != nil { _ = cacheManager.Write(databaseImage.ID, requestedSize, data) } return } // Serve full image - use http.ServeContent for *os.File to enable sendfile syscall if file, ok := reader.(*os.File); ok { http.ServeContent(w, r, "", time.Time{}, file) return } if _, err := io.Copy(w, reader); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } } func (rs imageRoutes) siteImage(w http.ResponseWriter, r *http.Request) { id := chi.URLParam(r, "uuid") siteID, err := uuid.FromString(id) if err != nil { w.WriteHeader(http.StatusNotFound) return } ctx := r.Context() site, err := rs.fac.Site().GetByID(ctx, siteID) if err != nil { return } data, err := storage.GetSiteIcon(r.Context(), *site) if err != nil { logger.Error("Couldn't get favicon:", err) } if data == nil { w.Header().Add("Cache-Control", "max-age=86400") w.WriteHeader(http.StatusNotFound) return } w.Header().Add("Cache-Control", "max-age=604800000") //nolint w.Write(data) } // Limit allowed sizes to prevent abuse var allowedSizes = []int{300, 600, 1280} func getImageSize(r *http.Request) (int, error) { maxSize := 0 querySize := r.FormValue("size") switch { case querySize == "full": // Skip resize case querySize != "": size, err := strconv.Atoi(querySize) if err != nil || !slices.Contains(allowedSizes, size) { return 0, err } return size, err case config.GetImageMaxSize() != nil: maxSize = *config.GetImageMaxSize() } return maxSize, nil } // shouldResize returns true if resize config is enabled, the size to resize to is not zero, // the image is not below the minimum size to ignore, and the image is larger than the minimum // size to resize down to. func shouldResize(image *models.Image, requestedSize int) bool { config := config.GetImageResizeConfig() minSize := config.MinSize return config.Enabled && requestedSize != 0 && (image.Width > minSize || image.Height > minSize) && (image.Width > requestedSize || image.Height > requestedSize) } ================================================ FILE: internal/api/routes_root.go ================================================ package api import ( "embed" "html/template" "io/fs" "net/http" "strings" "github.com/go-chi/chi/v5" "github.com/stashapp/stash-box/internal/config" "github.com/stashapp/stash-box/internal/service" ) type rootRoutes struct { ui embed.FS index []byte } func (rr rootRoutes) Routes(fac service.Factory) chi.Router { rr.index = getIndex(rr.ui) r := chi.NewRouter() // session handlers r.Post("/login", handleLogin(fac)) r.HandleFunc("/logout", handleLogout) r.Mount("/images", imageRoutes{ fac: fac, }.Routes()) // Serve static assets r.HandleFunc("/assets/*", rr.assets) r.HandleFunc("/favicon.ico", rr.assets) r.HandleFunc("/manifest.json", rr.assets) // Serve the web app r.HandleFunc("/*", rr.app) return r } func (rr rootRoutes) assets(w http.ResponseWriter, r *http.Request) { w.Header().Add("Cache-Control", "max-age=604800000") uiRoot, err := fs.Sub(rr.ui, "build") if err != nil { panic(error.Error(err)) } http.FileServer(http.FS(uiRoot)).ServeHTTP(w, r) } func (rr rootRoutes) app(w http.ResponseWriter, r *http.Request) { csp := config.GetCSP() if csp != "" { w.Header().Add("Content-Security-Policy", csp) } w.Header().Add("Strict-Transport-Security", "max-age=31536000; includeSubDomains") w.Header().Add("X-Content-Type-Options", "nosniff") w.Header().Add("Referrer-Policy", "same-origin") w.Header().Add("Permissions-Policy", "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()") _, _ = w.Write(rr.index) } func getIndex(ui embed.FS) []byte { indexFile, err := ui.ReadFile("build/index.html") if err != nil { panic(error.Error(err)) } tmpl := template.Must(template.New("index").Parse(string(indexFile))) title := template.HTMLEscapeString(config.GetTitle()) output := new(strings.Builder) if err := tmpl.Execute(output, template.HTML(title)); err != nil { panic(error.Error(err)) } return []byte(output.String()) } ================================================ FILE: internal/api/scene_edit_integration_test.go ================================================ //go:build integration package api_test import ( "fmt" "testing" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" "github.com/stretchr/testify/assert" ) type sceneEditTestRunner struct { testRunner } func createSceneEditTestRunner(t *testing.T) *sceneEditTestRunner { return &sceneEditTestRunner{ testRunner: *asAdmin(t), } } func (s *sceneEditTestRunner) testCreateSceneEdit() { sceneEditDetailsInput := s.createFullSceneEditDetailsInput() edit, err := s.createTestSceneEdit(models.OperationEnumCreate, sceneEditDetailsInput, nil) assert.NoError(s.t, err) s.verifyCreatedSceneEdit(*sceneEditDetailsInput, edit) } func (s *sceneEditTestRunner) verifyCreatedSceneEdit(input models.SceneEditDetailsInput, edit *models.Edit) { assert.True(s.t, edit.ID != uuid.Nil, "Expected created edit id to be non-zero") s.verifyEditOperation(models.OperationEnumCreate.String(), edit) s.verifyEditStatus(models.VoteStatusEnumPending.String(), edit) s.verifyEditTargetType(models.TargetTypeEnumScene.String(), edit) s.verifyEditApplication(false, edit) s.verifySceneEditDetails(input, edit) } func (s *sceneEditTestRunner) testFindEditById() { createdEdit, err := s.createTestSceneEdit(models.OperationEnumCreate, nil, nil) assert.NoError(s.t, err) edit, err := s.resolver.Query().FindEdit(s.ctx, createdEdit.ID) assert.NoError(s.t, err) assert.NotNil(s.t, edit, "Did not find edit by id") } func (s *sceneEditTestRunner) testModifySceneEdit() { existingTitle := "sceneName" existingDetails := "sceneDetails" existingProductionDate := "2020-03-01" sceneCreateInput := models.SceneCreateInput{ Title: &existingTitle, Details: &existingDetails, Date: "2020-03-02", ProductionDate: &existingProductionDate, } createdScene, err := s.createTestScene(&sceneCreateInput) assert.NoError(s.t, err) sceneEditDetailsInput := s.createSceneEditDetailsInput() id := createdScene.UUID() editInput := models.EditInput{ Operation: models.OperationEnumModify, ID: &id, } createdUpdateEdit, err := s.createTestSceneEdit(models.OperationEnumModify, sceneEditDetailsInput, &editInput) assert.NoError(s.t, err) s.verifyUpdatedSceneEdit(createdScene, *sceneEditDetailsInput, createdUpdateEdit) } func (s *sceneEditTestRunner) verifyUpdatedSceneEdit(originalScene *sceneOutput, input models.SceneEditDetailsInput, edit *models.Edit) { s.verifyEditOperation(models.OperationEnumModify.String(), edit) s.verifyEditStatus(models.VoteStatusEnumPending.String(), edit) s.verifyEditTargetType(models.TargetTypeEnumScene.String(), edit) s.verifyEditApplication(false, edit) s.verifySceneEditDetails(input, edit) } func (s *sceneEditTestRunner) verifySceneEditDetails(input models.SceneEditDetailsInput, edit *models.Edit) { sceneDetails := s.getEditSceneDetails(edit) c := fieldComparator{r: &s.testRunner} c.strPtrStrPtr(input.Title, sceneDetails.Title, "Title") c.strPtrStrPtr(input.Details, sceneDetails.Details, "Details") c.strPtrStrPtr(input.Director, sceneDetails.Director, "Director") c.strPtrStrPtr(input.Code, sceneDetails.Code, "Code") c.uuidPtrUUIDPtr(input.StudioID, sceneDetails.StudioID, "StudioID") c.intPtrIntPtr(input.Duration, sceneDetails.Duration, "Duration") c.strPtrStrPtr(input.Date, sceneDetails.Date, "Date") c.strPtrStrPtr(input.ProductionDate, sceneDetails.ProductionDate, "ProductionDate") assert.Equal(s.t, input.Urls, sceneDetails.AddedUrls) assert.Equal(s.t, input.ImageIds, sceneDetails.AddedImages) assert.Equal(s.t, input.TagIds, sceneDetails.AddedTags) if !comparePerformersInput(input.Performers, sceneDetails.AddedPerformers) { s.fieldMismatch(input.Performers, sceneDetails.AddedPerformers, "Performers") } } func (s *sceneEditTestRunner) verifySceneEdit(input models.SceneEditDetailsInput, scene *models.Scene) { resolver := s.resolver.Scene() c := fieldComparator{r: &s.testRunner} c.strPtrStrPtr(input.Title, scene.Title, "Title") c.strPtrStrPtr(input.Details, scene.Details, "Details") c.strPtrStrPtr(input.Director, scene.Director, "Director") c.strPtrStrPtr(input.Code, scene.Code, "Code") c.uuidPtrNullUUID(input.StudioID, scene.StudioID, "StudioID") c.intPtrIntPtr(input.Duration, scene.Duration, "Duration") c.strPtrStrPtr(input.Date, scene.Date, "Date") c.strPtrStrPtr(input.ProductionDate, scene.ProductionDate, "ProductionDate") urls, _ := resolver.Urls(s.ctx, scene) assert.Equal(s.t, input.Urls, urls) images, _ := resolver.Images(s.ctx, scene) var imageIds []uuid.UUID for _, image := range images { imageIds = append(imageIds, image.ID) } assert.Equal(s.t, input.ImageIds, imageIds) tags, _ := resolver.Tags(s.ctx, scene) var tagIdObjs []idObject for _, t := range tags { tagIdObjs = append(tagIdObjs, idObject{ID: t.ID.String()}) } if !compareTags(input.TagIds, tagIdObjs) { s.fieldMismatch(input.TagIds, tags, "Tags") } performers, _ := resolver.Performers(s.ctx, scene) var performerIdObjs []performerAppearance for _, p := range performers { performerIdObjs = append(performerIdObjs, performerAppearance{ Performer: &idObject{ ID: p.Performer.ID.String(), }, As: p.As, }) } if !comparePerformers(input.Performers, performerIdObjs) { s.fieldMismatch(input.Performers, performers, "Performers") } } func (s *sceneEditTestRunner) testDestroySceneEdit() { createdScene, err := s.createTestScene(nil) assert.NoError(s.t, err) sceneID := createdScene.UUID() sceneEditDetailsInput := models.SceneEditDetailsInput{} editInput := models.EditInput{ Operation: models.OperationEnumDestroy, ID: &sceneID, } destroyEdit, err := s.createTestSceneEdit(models.OperationEnumDestroy, &sceneEditDetailsInput, &editInput) assert.NoError(s.t, err) s.verifyDestroySceneEdit(sceneID, destroyEdit) } func (s *sceneEditTestRunner) verifyDestroySceneEdit(sceneID uuid.UUID, edit *models.Edit) { s.verifyEditOperation(models.OperationEnumDestroy.String(), edit) s.verifyEditStatus(models.VoteStatusEnumPending.String(), edit) s.verifyEditTargetType(models.TargetTypeEnumScene.String(), edit) s.verifyEditApplication(false, edit) editTarget := s.getEditSceneTarget(edit) assert.Equal(s.t, sceneID, editTarget.ID) } func (s *sceneEditTestRunner) testMergeSceneEdit() { existingName := "sceneName2" existingProductionDate := "2020-03-01" sceneCreateInput := models.SceneCreateInput{ Title: &existingName, Date: "2020-03-02", ProductionDate: &existingProductionDate, } createdPrimaryScene, err := s.createTestScene(&sceneCreateInput) assert.NoError(s.t, err) createdMergeScene, err := s.createTestScene(nil) sceneEditDetailsInput := s.createFullSceneEditDetailsInput() id := createdPrimaryScene.UUID() mergeSources := []uuid.UUID{createdMergeScene.UUID()} editInput := models.EditInput{ Operation: models.OperationEnumMerge, ID: &id, MergeSourceIds: mergeSources, } createdMergeEdit, err := s.createTestSceneEdit(models.OperationEnumMerge, sceneEditDetailsInput, &editInput) assert.NoError(s.t, err) s.verifyMergeSceneEdit(createdPrimaryScene, *sceneEditDetailsInput, createdMergeEdit, mergeSources) } func (s *sceneEditTestRunner) verifyMergeSceneEdit(originalScene *sceneOutput, input models.SceneEditDetailsInput, edit *models.Edit, inputMergeSources []uuid.UUID) { s.verifyEditOperation(models.OperationEnumMerge.String(), edit) s.verifyEditStatus(models.VoteStatusEnumPending.String(), edit) s.verifyEditTargetType(models.TargetTypeEnumScene.String(), edit) s.verifyEditApplication(false, edit) s.verifySceneEditDetails(input, edit) var mergeSources []uuid.UUID merges, _ := s.resolver.Edit().MergeSources(s.ctx, edit) for i := range merges { merge := merges[i].(*models.Scene) mergeSources = append(mergeSources, merge.ID) } assert.Equal(s.t, inputMergeSources, mergeSources) } func (s *sceneEditTestRunner) testApplyCreateSceneEdit() { sceneEditDetailsInput := s.createFullSceneEditDetailsInput() edit, err := s.createTestSceneEdit(models.OperationEnumCreate, sceneEditDetailsInput, nil) appliedEdit, err := s.applyEdit(edit.ID) assert.NoError(s.t, err) s.verifyAppliedSceneCreateEdit(*sceneEditDetailsInput, appliedEdit) } func (s *sceneEditTestRunner) verifyAppliedSceneCreateEdit(input models.SceneEditDetailsInput, edit *models.Edit) { assert.True(s.t, edit.ID != uuid.Nil) s.verifyEditOperation(models.OperationEnumCreate.String(), edit) s.verifyEditStatus(models.VoteStatusEnumImmediateAccepted.String(), edit) s.verifyEditTargetType(models.TargetTypeEnumScene.String(), edit) s.verifyEditApplication(true, edit) scene := s.getEditSceneTarget(edit) s.verifySceneEdit(input, scene) } func (s *sceneEditTestRunner) testApplyModifySceneEdit() { title := "sceneName3" productionDate := "2020-03-01" site, err := s.createTestSite(nil) assert.NoError(s.t, err) sceneCreateInput := models.SceneCreateInput{ Title: &title, Urls: []models.URL{ { URL: "http://example.org/asd", SiteID: site.ID, }, }, Date: "2020-03-02", ProductionDate: &productionDate, } createdScene, err := s.createTestScene(&sceneCreateInput) assert.NoError(s.t, err) // Create edit that replaces all metadata for the scene sceneEditDetailsInput := s.createFullSceneEditDetailsInput() id := createdScene.UUID() editInput := models.EditInput{ Operation: models.OperationEnumModify, ID: &id, } createdUpdateEdit, err := s.createTestSceneEdit(models.OperationEnumModify, sceneEditDetailsInput, &editInput) assert.NoError(s.t, err) appliedEdit, err := s.applyEdit(createdUpdateEdit.ID) assert.NoError(s.t, err) modifiedScene, _ := s.resolver.Query().FindScene(s.ctx, id) s.verifyApplyModifySceneEdit(*sceneEditDetailsInput, modifiedScene, appliedEdit) } func (s *sceneEditTestRunner) verifyApplyModifySceneEdit(input models.SceneEditDetailsInput, updatedScene *models.Scene, edit *models.Edit) { s.verifyEditOperation(models.OperationEnumModify.String(), edit) s.verifyEditStatus(models.VoteStatusEnumImmediateAccepted.String(), edit) s.verifyEditTargetType(models.TargetTypeEnumScene.String(), edit) s.verifyEditApplication(true, edit) s.verifySceneEdit(input, updatedScene) } func (s *sceneEditTestRunner) testApplyModifyUnsetSceneEdit() { sceneData := s.createFullSceneCreateInput() createdScene, err := s.createTestScene(sceneData) assert.NoError(s.t, err) id := createdScene.UUID() var resp struct { SceneEdit struct { ID string } } s.client.MustPost(fmt.Sprintf(` mutation { sceneEdit(input: { edit: {id: "%v", operation: MODIFY} details: { urls: [], director: null } }) { id } } `, id), &resp) edit, _ := s.applyEdit(uuid.FromStringOrNil(resp.SceneEdit.ID)) s.verifyAppliedSceneEdit(edit) var scene struct { FindScene struct { Director string URLs []models.URL Tags []models.Tag } } s.client.MustPost(fmt.Sprintf(` query { findScene(id: "%v") { director urls { url } tags { id } } } `, id), &scene) assert.Equal(s.t, scene.FindScene.Director, "") assert.True(s.t, len(scene.FindScene.URLs) == 0) assert.True(s.t, len(scene.FindScene.Tags) == len(sceneData.TagIds)) } func (s *sceneEditTestRunner) testApplyDestroySceneEdit() { createdScene, err := s.createTestScene(nil) assert.NoError(s.t, err) sceneID := createdScene.UUID() sceneEditDetailsInput := models.SceneEditDetailsInput{} editInput := models.EditInput{ Operation: models.OperationEnumDestroy, ID: &sceneID, } destroyEdit, err := s.createTestSceneEdit(models.OperationEnumDestroy, &sceneEditDetailsInput, &editInput) assert.NoError(s.t, err) appliedEdit, err := s.applyEdit(destroyEdit.ID) destroyedScene, _ := s.resolver.Query().FindScene(s.ctx, sceneID) s.verifyApplyDestroySceneEdit(destroyedScene, appliedEdit) } func (s *sceneEditTestRunner) verifyApplyDestroySceneEdit(destroyedScene *models.Scene, edit *models.Edit) { s.verifyEditOperation(models.OperationEnumDestroy.String(), edit) s.verifyEditStatus(models.VoteStatusEnumImmediateAccepted.String(), edit) s.verifyEditTargetType(models.TargetTypeEnumScene.String(), edit) s.verifyEditApplication(true, edit) assert.Equal(s.t, destroyedScene.Deleted, true) } func (s *sceneEditTestRunner) testApplyMergeSceneEdit() { mergeSource1, err := s.createTestScene(nil) assert.NoError(s.t, err) mergeSource2, err := s.createTestScene(nil) assert.NoError(s.t, err) mergeTarget, err := s.createTestScene(nil) assert.NoError(s.t, err) sceneEditDetailsInput := s.createFullSceneEditDetailsInput() mergeSources := []uuid.UUID{ mergeSource1.UUID(), mergeSource2.UUID(), } id := mergeTarget.UUID() editInput := models.EditInput{ Operation: models.OperationEnumMerge, ID: &id, MergeSourceIds: mergeSources, } mergeEdit, err := s.createTestSceneEdit(models.OperationEnumMerge, sceneEditDetailsInput, &editInput) assert.NoError(s.t, err) appliedMerge, err := s.applyEdit(mergeEdit.ID) assert.NoError(s.t, err) s.verifyAppliedMergeSceneEdit(*sceneEditDetailsInput, appliedMerge) } func (s *sceneEditTestRunner) verifyAppliedMergeSceneEdit(input models.SceneEditDetailsInput, edit *models.Edit) { s.verifyEditOperation(models.OperationEnumMerge.String(), edit) s.verifyEditStatus(models.VoteStatusEnumImmediateAccepted.String(), edit) s.verifyEditTargetType(models.TargetTypeEnumScene.String(), edit) s.verifyEditApplication(true, edit) s.verifySceneEditDetails(input, edit) merges, _ := s.resolver.Edit().MergeSources(s.ctx, edit) for i := range merges { scene := merges[i].(*models.Scene) assert.Equal(s.t, scene.Deleted, true) } } func (s *sceneEditTestRunner) testQueryExistingScene() { studio, err := s.createTestStudio(nil) assert.NoError(s.t, err) sceneEditDetailsInput := s.createFullSceneEditDetailsInput() sceneEditDetailsInput.Fingerprints = []models.FingerprintInput{{ Hash: models.FingerprintHash(0xa5d), Algorithm: models.FingerprintAlgorithmPhash, Duration: 123, }} studioID := studio.UUID() sceneEditDetailsInput.StudioID = &studioID edit, err := s.createTestSceneEdit(models.OperationEnumCreate, sceneEditDetailsInput, nil) assert.NoError(s.t, err) var resp struct { QueryExistingScene struct { Edits []struct { ID string } } } s.client.MustPost(fmt.Sprintf(` query { queryExistingScene(input: { title: "%v" studio_id: "%v" fingerprints: [{ duration: 123 hash: "%v" algorithm: %v }] }) { edits { id } } } `, *sceneEditDetailsInput.Title, sceneEditDetailsInput.StudioID, sceneEditDetailsInput.Fingerprints[0].Hash, sceneEditDetailsInput.Fingerprints[0].Algorithm), &resp) assert.True(s.t, len(resp.QueryExistingScene.Edits) > 0) _, err = s.resolver.Mutation().CancelEdit(s.ctx, models.CancelEditInput{ ID: edit.ID, }) assert.NoError(s.t, err) s.client.MustPost(fmt.Sprintf(` query { queryExistingScene(input: { title: "%v" studio_id: "%v" fingerprints: [{ duration: 123 hash: "%v" algorithm: %v }] }) { edits { id } } } `, *sceneEditDetailsInput.Title, sceneEditDetailsInput.StudioID, sceneEditDetailsInput.Fingerprints[0].Hash, sceneEditDetailsInput.Fingerprints[0].Algorithm), &resp) assert.True(s.t, len(resp.QueryExistingScene.Edits) == 0) } func (s *sceneEditTestRunner) testSceneEditUpdate() { // Create a pending edit sceneEditDetailsInput := s.createSceneEditDetailsInput() createdEdit, err := s.createTestSceneEdit(models.OperationEnumCreate, sceneEditDetailsInput, nil) assert.NoError(s.t, err) // Update the edit with new details newTitle := "Updated Title" updatedDetails := models.SceneEditDetailsInput{ Title: &newTitle, } editID := createdEdit.ID updatedEdit, err := s.resolver.Mutation().SceneEditUpdate(s.ctx, createdEdit.ID, models.SceneEditInput{ Edit: &models.EditInput{ID: &editID}, Details: &updatedDetails, }) assert.NoError(s.t, err, "Error updating scene edit") // Verify the edit was updated assert.Equal(s.t, createdEdit.ID, updatedEdit.ID, "Edit ID should not change") assert.NotNil(s.t, updatedEdit, "Updated edit should not be nil") } func TestCreateSceneEdit(t *testing.T) { pt := createSceneEditTestRunner(t) pt.testCreateSceneEdit() } func TestModifySceneEdit(t *testing.T) { pt := createSceneEditTestRunner(t) pt.testModifySceneEdit() } func TestDestroySceneEdit(t *testing.T) { pt := createSceneEditTestRunner(t) pt.testDestroySceneEdit() } func TestMergeSceneEdit(t *testing.T) { pt := createSceneEditTestRunner(t) pt.testMergeSceneEdit() } func TestApplyCreateSceneEdit(t *testing.T) { pt := createSceneEditTestRunner(t) pt.testApplyCreateSceneEdit() } func TestApplyModifySceneEdit(t *testing.T) { pt := createSceneEditTestRunner(t) pt.testApplyModifySceneEdit() } func TestApplyModifyUnsetSceneEdit(t *testing.T) { pt := createSceneEditTestRunner(t) pt.testApplyModifyUnsetSceneEdit() } func TestApplyDestroySceneEdit(t *testing.T) { pt := createSceneEditTestRunner(t) pt.testApplyDestroySceneEdit() } func TestApplyMergeSceneEdit(t *testing.T) { pt := createSceneEditTestRunner(t) pt.testApplyMergeSceneEdit() } func TestQueryExistingScene(t *testing.T) { pt := createSceneEditTestRunner(t) pt.testQueryExistingScene() } func TestSceneEditUpdate(t *testing.T) { pt := createSceneEditTestRunner(t) pt.testSceneEditUpdate() } ================================================ FILE: internal/api/scene_integration_test.go ================================================ //go:build integration package api_test import ( "fmt" "testing" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/config" "github.com/stashapp/stash-box/internal/models" "github.com/stretchr/testify/assert" ) type sceneTestRunner struct { testRunner } func createSceneTestRunner(t *testing.T) *sceneTestRunner { return &sceneTestRunner{ testRunner: *asAdmin(t), } } func (s *sceneTestRunner) testCreateScene() { title := "Title" details := "Details" date := "2003-02-01" production_date := "2003-03-09" performer, _ := s.createTestPerformer(nil) studio, _ := s.createTestStudio(nil) tag, _ := s.createTestTag(nil) site, _ := s.createTestSite(nil) performerID := performer.UUID() studioID := studio.UUID() tagID := tag.UUID() performerAlias := "alias" input := models.SceneCreateInput{ Title: &title, Details: &details, Date: date, ProductionDate: &production_date, Fingerprints: []models.FingerprintEditInput{ s.generateSceneFingerprint(nil), }, StudioID: &studioID, Performers: []models.PerformerAppearanceInput{ { PerformerID: performerID, As: &performerAlias, }, }, Urls: []models.URL{ { URL: "URL", SiteID: site.ID, }, }, TagIds: []uuid.UUID{ tagID, }, } scene, err := s.client.createScene(input) assert.NoError(s.t, err) s.verifyCreatedScene(input, scene) } func (s *sceneTestRunner) verifyCreatedScene(input models.SceneCreateInput, scene *sceneOutput) { // ensure basic attributes are set correctly assert.True(s.t, scene.ID != "", "Expected created scene id to be non-zero") assert.Equal(s.t, scene.Title, input.Title) assert.Equal(s.t, scene.Details, input.Details) s.compareSiteURLs(input.Urls, scene.Urls) assert.True(s.t, bothNil(scene.Date, input.Date) || (!oneNil(scene.Date, input.Date) && input.Date == *scene.Date)) assert.True(s.t, bothNil(scene.ProductionDate, input.ProductionDate) || (!oneNil(scene.ProductionDate, input.ProductionDate) && *input.ProductionDate == *scene.ProductionDate)) assert.True(s.t, compareFingerprints(input.Fingerprints, scene.Fingerprints)) assert.True(s.t, comparePerformers(input.Performers, scene.Performers)) assert.True(s.t, compareTags(input.TagIds, scene.Tags)) } func (s *sceneTestRunner) testFindSceneById() { createdScene, err := s.createTestScene(nil) assert.NoError(s.t, err) scene, err := s.client.findScene(createdScene.UUID()) assert.NoError(s.t, err) // ensure returned scene is not nil assert.NotNil(s.t, scene, "Did not find scene by id") // ensure values were set assert.Equal(s.t, *createdScene.Title, *scene.Title) } func (s *sceneTestRunner) testUpdateScene() { title := "Title" details := "Details" date := "2003-02-01" production_date := "2003-01-30" performer, _ := s.createTestPerformer(nil) studio, _ := s.createTestStudio(nil) tag, _ := s.createTestTag(nil) site, _ := s.createTestSite(nil) performerID := performer.UUID() studioID := studio.UUID() tagID := tag.UUID() performerAlias := "alias" input := models.SceneCreateInput{ Title: &title, Details: &details, Date: date, ProductionDate: &production_date, Fingerprints: []models.FingerprintEditInput{ // fingerprint that will be kept s.generateSceneFingerprint([]uuid.UUID{ userDB.none.ID, userDB.admin.ID, }), // fingerprint that will be removed s.generateSceneFingerprint(nil), }, StudioID: &studioID, Performers: []models.PerformerAppearanceInput{ { PerformerID: performerID, As: &performerAlias, }, }, Urls: []models.URL{ { URL: "URL", SiteID: site.ID, }, }, TagIds: []uuid.UUID{ tagID, }, } createdScene, err := s.createTestScene(&input) assert.NoError(s.t, err) newTitle := "NewTitle" newDetails := "NewDetails" newDate := "2001-02-03" newProductionDate := "2001-02-01" performer, _ = s.createTestPerformer(nil) studio, _ = s.createTestStudio(nil) tag, _ = s.createTestTag(nil) site, _ = s.createTestSite(nil) performerID = performer.UUID() studioID = studio.UUID() tagID = tag.UUID() performerAlias = "updatedAlias" sceneID := createdScene.UUID() updateInput := models.SceneUpdateInput{ ID: sceneID, Title: &newTitle, Details: &newDetails, Date: &newDate, ProductionDate: &newProductionDate, Fingerprints: []models.FingerprintEditInput{ input.Fingerprints[0], s.generateSceneFingerprint(nil), }, Performers: []models.PerformerAppearanceInput{ { PerformerID: performerID, As: &performerAlias, }, }, Urls: []models.URL{ { URL: "URL", SiteID: site.ID, }, }, StudioID: &studioID, TagIds: []uuid.UUID{ tagID, }, } scene, err := s.client.updateScene(updateInput) assert.NoError(s.t, err) s.verifyUpdatedScene(updateInput, scene) // ensure fingerprint changes were enacted s.verifyUpdatedFingerprints(input.Fingerprints, updateInput.Fingerprints, scene) // ensure submissions count was maintained originalFP := input.Fingerprints[0] foundFP := false for _, f := range scene.Fingerprints { if originalFP.Algorithm == f.Algorithm && originalFP.Hash.Hex() == f.Hash { foundFP = true assert.Equal(s.t, f.Submissions, 2, "Incorrect fingerprint submissions count") } } assert.True(s.t, foundFP, "Could not find original fingerprint") } func (s *sceneTestRunner) verifyUpdatedScene(input models.SceneUpdateInput, scene *sceneOutput) { // ensure basic attributes are set correctly assert.Equal(s.t, scene.Title, input.Title) assert.Equal(s.t, scene.Details, input.Details) assert.True(s.t, bothNil(scene.Date, input.Date) || (!oneNil(scene.Date, input.Date) && *scene.Date == *input.Date)) assert.True(s.t, bothNil(scene.ProductionDate, input.ProductionDate) || (!oneNil(scene.ProductionDate, input.ProductionDate) && *scene.ProductionDate == *input.ProductionDate)) s.compareSiteURLs(input.Urls, scene.Urls) assert.True(s.t, comparePerformers(input.Performers, scene.Performers)) assert.True(s.t, compareTags(input.TagIds, scene.Tags)) } func (s *sceneTestRunner) verifyUpdatedFingerprints(original, updated []models.FingerprintEditInput, scene *sceneOutput) { hashExists := func(h models.FingerprintEditInput, vs []models.FingerprintEditInput) bool { for _, v := range vs { if h.Algorithm == v.Algorithm && h.Hash == v.Hash { return true } } return false } inOutput := func(h models.FingerprintEditInput) bool { for _, hh := range scene.Fingerprints { if hh.Algorithm == h.Algorithm && hh.Hash == h.Hash.Hex() { return true } } return false } for _, o := range original { // find in updated if hashExists(o, updated) { // exists, so ensure hash exists in output assert.True(s.t, inOutput(o), "existing hash s missing in output") } else { // not exists, ensure not in output assert.True(s.t, !inOutput(o), "removed hash %s still in output") } } for _, u := range updated { // find in original if !hashExists(u, original) { // new hash, ensure in output assert.True(s.t, inOutput(u), "new hash missing in output") } } } func (s *sceneTestRunner) testDestroyScene() { createdScene, err := s.createTestScene(nil) assert.NoError(s.t, err) sceneID := createdScene.UUID() destroyed, err := s.client.destroyScene(models.SceneDestroyInput{ ID: sceneID, }) assert.NoError(s.t, err, "Error destroying scene") assert.True(s.t, destroyed, "Scene was not destroyed") // ensure cannot find scene foundScene, err := s.client.findScene(sceneID) assert.NoError(s.t, err, "Error finding scene after destroying") assert.Nil(s.t, foundScene, "Found scene after destruction") // TODO - ensure scene was not removed } func (s *sceneTestRunner) testSubmitFingerprint() { createdScene, err := s.createTestScene(nil) assert.NoError(s.t, err) fp := s.generateSceneFingerprint(nil) _, err = s.client.submitFingerprint(models.FingerprintSubmission{ SceneID: createdScene.UUID(), Fingerprint: &models.FingerprintInput{ Hash: fp.Hash, Algorithm: fp.Algorithm, Duration: fp.Duration, }, }) assert.NoError(s.t, err, "Error submitting fingerprint") scene, err := s.client.findScene(createdScene.UUID()) assert.NoError(s.t, err, "Error finding scene") // verify created fingerprint expected := fingerprint{ Hash: fp.Hash.Hex(), Algorithm: fp.Algorithm, Duration: fp.Duration, Submissions: 1, } actualFP := scene.Fingerprints[1] actual := fingerprint{ Hash: actualFP.Hash, Algorithm: actualFP.Algorithm, Duration: actualFP.Duration, Submissions: actualFP.Submissions, } assert.Equal(s.t, actual, expected) // submit the same fingerprint - should not add and should not error _, err = s.client.submitFingerprint(models.FingerprintSubmission{ SceneID: createdScene.UUID(), Fingerprint: &models.FingerprintInput{ Hash: fp.Hash, Algorithm: fp.Algorithm, Duration: fp.Duration, }, }) assert.NoError(s.t, err, "Error submitting fingerprint") } func (s *sceneTestRunner) testSubmitFingerprintUnmatch() { createdScene, err := s.createTestScene(nil) assert.NoError(s.t, err) unmatch := true _, err = s.client.submitFingerprint(models.FingerprintSubmission{ SceneID: createdScene.UUID(), Fingerprint: &models.FingerprintInput{ Hash: createdScene.Fingerprints[0].FingerprintHash(), Algorithm: createdScene.Fingerprints[0].Algorithm, Duration: createdScene.Fingerprints[0].Duration, }, Unmatch: &unmatch, }) assert.NoError(s.t, err, "Error submitting fingerprint") scene, err := s.client.findScene(createdScene.UUID()) assert.NoError(s.t, err) assert.True(s.t, len(scene.Fingerprints) == 0) } func (s *sceneTestRunner) testSubmitFingerprintModify() { createdScene, err := s.createTestScene(nil) assert.NoError(s.t, err) fp := s.generateSceneFingerprint(nil) _, err = s.client.submitFingerprint(models.FingerprintSubmission{ SceneID: createdScene.UUID(), Fingerprint: &models.FingerprintInput{ Hash: fp.Hash, Algorithm: fp.Algorithm, Duration: fp.Duration, UserIds: []uuid.UUID{ userDB.edit.ID, userDB.none.ID, userDB.read.ID, }, }, }) assert.NoError(s.t, err, "Error submitting fingerprint") scene, err := s.client.findScene(createdScene.UUID()) assert.NoError(s.t, err) // verify created fingerprint expected := fingerprint{ Hash: fp.Hash.Hex(), Algorithm: fp.Algorithm, Duration: fp.Duration, Submissions: 3, } actualFP := scene.Fingerprints[0] actual := fingerprint{ Hash: actualFP.Hash, Algorithm: actualFP.Algorithm, Duration: actualFP.Duration, Submissions: actualFP.Submissions, } assert.Equal(s.t, actual, expected) // submit the same fingerprint - should add _, err = s.client.submitFingerprint(models.FingerprintSubmission{ SceneID: createdScene.UUID(), Fingerprint: &models.FingerprintInput{ Hash: fp.Hash, Algorithm: fp.Algorithm, Duration: fp.Duration, }, }) assert.NoError(s.t, err, "Error submitting fingerprint") scene, err = s.client.findScene(createdScene.UUID()) assert.NoError(s.t, err) expected.Submissions = 4 actual.Submissions = scene.Fingerprints[0].Submissions assert.Equal(s.t, actual, expected) } func (s *sceneTestRunner) testSubmitFingerprintUnmatchModify() { createdScene, err := s.createTestScene(nil) assert.NoError(s.t, err) fp := s.generateSceneFingerprint(nil) _, err = s.client.submitFingerprint(models.FingerprintSubmission{ SceneID: createdScene.UUID(), Fingerprint: &models.FingerprintInput{ Hash: fp.Hash, Algorithm: fp.Algorithm, Duration: fp.Duration, UserIds: []uuid.UUID{ userDB.edit.ID, userDB.none.ID, userDB.read.ID, }, }, }) assert.NoError(s.t, err, "Error submitting fingerprint") unmatch := true _, err = s.client.submitFingerprint(models.FingerprintSubmission{ SceneID: createdScene.UUID(), Fingerprint: &models.FingerprintInput{ Hash: fp.Hash, Algorithm: fp.Algorithm, Duration: fp.Duration, UserIds: []uuid.UUID{ userDB.edit.ID, }, }, Unmatch: &unmatch, }) assert.NoError(s.t, err, "Error submitting fingerprint") scene, err := s.client.findScene(createdScene.UUID()) assert.NoError(s.t, err) expected := fingerprint{ Hash: fp.Hash.Hex(), Algorithm: fp.Algorithm, Duration: fp.Duration, Submissions: 2, } actualFP := scene.Fingerprints[0] actual := fingerprint{ Hash: actualFP.Hash, Algorithm: actualFP.Algorithm, Duration: actualFP.Duration, Submissions: actualFP.Submissions, } assert.Equal(s.t, actual, expected) } func (s *sceneTestRunner) verifyQueryScenesResult(filter models.SceneQueryInput, ids []uuid.UUID) { s.t.Helper() filter.Page = 1 filter.PerPage = 10 filter.Sort = models.SceneSortEnumTitle filter.Direction = models.SortDirectionEnumAsc results, err := s.client.queryScenes(filter) assert.NoError(s.t, err) assert.Equal(s.t, results.Count, len(ids)) for _, id := range ids { found := false for _, scene := range results.Scenes { if scene.ID == id.String() { found = true break } } assert.True(s.t, found, "Missing scene") } } func (s *sceneTestRunner) verifyInvalidModifier(filter models.SceneQueryInput) { s.t.Helper() filter.Page = 1 filter.PerPage = 10 resolver, _ := s.resolver.Query().QueryScenes(s.ctx, filter) _, err := s.resolver.QueryScenesResultType().Scenes(s.ctx, resolver) assert.ErrorContains(s.t, err, "unsupported modifier") } func (s *sceneTestRunner) testQueryScenesByStudio() { studio1, _ := s.createTestStudio(nil) studio2, _ := s.createTestStudio(nil) studio1ID := studio1.UUID() studio2ID := studio2.UUID() prefix := "testQueryScenesByStudio_" scene1Title := prefix + "scene1Title" scene2Title := prefix + "scene2Title" scene3Title := prefix + "scene3Title" input := models.SceneCreateInput{ StudioID: &studio1ID, Title: &scene1Title, Date: "2020-03-02", } scene1, err := s.createTestScene(&input) assert.NoError(s.t, err) input.StudioID = &studio2ID input.Title = &scene2Title scene2, err := s.createTestScene(&input) assert.NoError(s.t, err) input.StudioID = nil input.Title = &scene3Title scene3, err := s.createTestScene(&input) assert.NoError(s.t, err) scene1ID := scene1.UUID() scene2ID := scene2.UUID() scene3ID := scene3.UUID() // test equals filter := models.SceneQueryInput{ Studios: &models.MultiIDCriterionInput{ Value: []uuid.UUID{studio1ID}, Modifier: models.CriterionModifierEquals, }, } s.verifyQueryScenesResult(filter, []uuid.UUID{scene1ID}) filter.Studios.Modifier = models.CriterionModifierNotEquals filter.Title = &scene2Title s.verifyQueryScenesResult(filter, []uuid.UUID{scene2ID}) filter.Studios.Modifier = models.CriterionModifierIsNull filter.Title = &scene3Title s.verifyQueryScenesResult(filter, []uuid.UUID{scene3ID}) filter.Studios.Modifier = models.CriterionModifierNotNull filter.Title = &scene1Title s.verifyQueryScenesResult(filter, []uuid.UUID{scene1ID}) filter.Studios.Modifier = models.CriterionModifierIncludes filter.Studios.Value = []uuid.UUID{studio1ID, studio2ID} filter.Title = nil s.verifyQueryScenesResult(filter, []uuid.UUID{scene1ID, scene2ID}) filter.Studios.Modifier = models.CriterionModifierExcludes filter.Studios.Value = []uuid.UUID{studio1ID} filter.Title = &scene2Title s.verifyQueryScenesResult(filter, []uuid.UUID{scene2ID}) // test invalid modifiers filter.Studios.Modifier = models.CriterionModifierGreaterThan s.verifyInvalidModifier(filter) filter.Studios.Modifier = models.CriterionModifierLessThan s.verifyInvalidModifier(filter) filter.Studios.Modifier = models.CriterionModifierIncludesAll s.verifyInvalidModifier(filter) } func (s *sceneTestRunner) testQueryScenesByPerformer() { performer1, _ := s.createTestPerformer(nil) performer2, _ := s.createTestPerformer(nil) performer1ID := performer1.UUID() performer2ID := performer2.UUID() prefix := "testQueryScenesByPerformer_" scene1Title := prefix + "scene1Title" scene2Title := prefix + "scene2Title" scene3Title := prefix + "scene3Title" input := models.SceneCreateInput{ Performers: []models.PerformerAppearanceInput{ { PerformerID: performer1ID, }, }, Title: &scene1Title, Date: "2020-03-02", } scene1, err := s.createTestScene(&input) assert.NoError(s.t, err) input.Performers[0].PerformerID = performer2ID input.Title = &scene2Title scene2, err := s.createTestScene(&input) assert.NoError(s.t, err) input.Performers = append(input.Performers, models.PerformerAppearanceInput{ PerformerID: performer1ID, }) input.Title = &scene3Title scene3, err := s.createTestScene(&input) assert.NoError(s.t, err) scene1ID := scene1.UUID() scene2ID := scene2.UUID() scene3ID := scene3.UUID() titleSearch := prefix filter := models.SceneQueryInput{ Performers: &models.MultiIDCriterionInput{ Value: []uuid.UUID{performer1ID}, Modifier: models.CriterionModifierIncludes, }, Title: &titleSearch, } s.verifyQueryScenesResult(filter, []uuid.UUID{scene1ID, scene3ID}) filter.Performers.Modifier = models.CriterionModifierExcludes s.verifyQueryScenesResult(filter, []uuid.UUID{scene2ID}) filter.Performers.Modifier = models.CriterionModifierIncludesAll filter.Performers.Value = append(filter.Performers.Value, performer2ID) s.verifyQueryScenesResult(filter, []uuid.UUID{scene3ID}) // test INCLUDES with multiple performers - scene3 has both performers and should appear only once filter.Performers.Modifier = models.CriterionModifierIncludes filter.Performers.Value = []uuid.UUID{performer1ID, performer2ID} s.verifyQueryScenesResult(filter, []uuid.UUID{scene1ID, scene2ID, scene3ID}) // test invalid modifiers filter.Performers.Modifier = models.CriterionModifierGreaterThan s.verifyInvalidModifier(filter) filter.Performers.Modifier = models.CriterionModifierLessThan s.verifyInvalidModifier(filter) filter.Performers.Modifier = models.CriterionModifierEquals s.verifyInvalidModifier(filter) filter.Performers.Modifier = models.CriterionModifierNotEquals s.verifyInvalidModifier(filter) filter.Performers.Modifier = models.CriterionModifierIsNull s.verifyInvalidModifier(filter) filter.Performers.Modifier = models.CriterionModifierNotNull s.verifyInvalidModifier(filter) } func (s *sceneTestRunner) testQueryScenesByTag() { tag1, _ := s.createTestTag(nil) tag2, _ := s.createTestTag(nil) tag1ID := tag1.UUID() tag2ID := tag2.UUID() prefix := "testQueryScenesByTag_" scene1Title := prefix + "scene1Title" scene2Title := prefix + "scene2Title" scene3Title := prefix + "scene3Title" input := models.SceneCreateInput{ TagIds: []uuid.UUID{ tag1ID, }, Title: &scene1Title, Date: "2020-03-02", } scene1, err := s.createTestScene(&input) assert.NoError(s.t, err) input.TagIds[0] = tag2ID input.Title = &scene2Title scene2, err := s.createTestScene(&input) assert.NoError(s.t, err) input.TagIds = append(input.TagIds, tag1ID) input.Title = &scene3Title scene3, err := s.createTestScene(&input) assert.NoError(s.t, err) scene1ID := scene1.UUID() scene2ID := scene2.UUID() scene3ID := scene3.UUID() titleSearch := prefix filter := models.SceneQueryInput{ Tags: &models.MultiIDCriterionInput{ Value: []uuid.UUID{tag1ID}, Modifier: models.CriterionModifierIncludes, }, Title: &titleSearch, } s.verifyQueryScenesResult(filter, []uuid.UUID{scene1ID, scene3ID}) filter.Tags.Modifier = models.CriterionModifierExcludes s.verifyQueryScenesResult(filter, []uuid.UUID{scene2ID}) filter.Tags.Modifier = models.CriterionModifierIncludesAll filter.Tags.Value = append(filter.Tags.Value, tag2ID) s.verifyQueryScenesResult(filter, []uuid.UUID{scene3ID}) // test INCLUDES with multiple tags - scene3 has both tags and should appear only once filter.Tags.Modifier = models.CriterionModifierIncludes filter.Tags.Value = []uuid.UUID{tag1ID, tag2ID} s.verifyQueryScenesResult(filter, []uuid.UUID{scene1ID, scene2ID, scene3ID}) // test invalid modifiers filter.Tags.Modifier = models.CriterionModifierGreaterThan s.verifyInvalidModifier(filter) filter.Tags.Modifier = models.CriterionModifierLessThan s.verifyInvalidModifier(filter) filter.Tags.Modifier = models.CriterionModifierEquals s.verifyInvalidModifier(filter) filter.Tags.Modifier = models.CriterionModifierNotEquals s.verifyInvalidModifier(filter) filter.Tags.Modifier = models.CriterionModifierIsNull s.verifyInvalidModifier(filter) filter.Tags.Modifier = models.CriterionModifierNotNull s.verifyInvalidModifier(filter) } func TestCreateScene(t *testing.T) { pt := createSceneTestRunner(t) pt.testCreateScene() } func TestFindSceneById(t *testing.T) { pt := createSceneTestRunner(t) pt.testFindSceneById() } func TestUpdateScene(t *testing.T) { pt := createSceneTestRunner(t) pt.testUpdateScene() } // TestUpdateSceneTitle is removed due to no longer allowing // partial updates func TestDestroyScene(t *testing.T) { pt := createSceneTestRunner(t) pt.testDestroyScene() } func TestQueryScenesByStudio(t *testing.T) { pt := createSceneTestRunner(t) pt.testQueryScenesByStudio() } func TestQueryScenesByPerformer(t *testing.T) { pt := createSceneTestRunner(t) pt.testQueryScenesByPerformer() } func TestQueryScenesByTag(t *testing.T) { pt := createSceneTestRunner(t) pt.testQueryScenesByTag() } func TestSubmitFingerprint(t *testing.T) { pt := createSceneTestRunner(t) pt.testSubmitFingerprint() } func TestSubmitFingerprintUnmatch(t *testing.T) { pt := createSceneTestRunner(t) pt.testSubmitFingerprintUnmatch() } func TestSubmitFingerprintModify(t *testing.T) { pt := createSceneTestRunner(t) pt.testSubmitFingerprintModify() } func TestSubmitFingerprintUnmatchModify(t *testing.T) { pt := createSceneTestRunner(t) pt.testSubmitFingerprintUnmatchModify() } func TestSubmitFingerprintsBatch(t *testing.T) { pt := createSceneTestRunner(t) pt.testSubmitFingerprintsBatch() } func TestSubmitFingerprintsBatchMixedResults(t *testing.T) { pt := createSceneTestRunner(t) pt.testSubmitFingerprintsBatchMixedResults() } func TestSubmitFingerprintsBatchMaxLimit(t *testing.T) { pt := createSceneTestRunner(t) pt.testSubmitFingerprintsBatchMaxLimit() } func (s *sceneTestRunner) testSubmitFingerprintsBatch() { // Create multiple test scenes scene1, err := s.createTestScene(nil) assert.NoError(s.t, err) scene2, err := s.createTestScene(nil) assert.NoError(s.t, err) // Generate fingerprints for each scene fp1 := s.generateSceneFingerprint(nil) fp2 := s.generateSceneFingerprint(nil) // Submit batch of fingerprints results, err := s.client.submitFingerprints([]models.FingerprintBatchSubmission{ { SceneID: scene1.UUID(), Hash: fp1.Hash, Algorithm: fp1.Algorithm, Duration: fp1.Duration, }, { SceneID: scene2.UUID(), Hash: fp2.Hash, Algorithm: fp2.Algorithm, Duration: fp2.Duration, }, }) assert.NoError(s.t, err, "Error submitting fingerprints") assert.Len(s.t, results, 2) // Verify both results succeeded (no errors) assert.Nil(s.t, results[0].Error) assert.Nil(s.t, results[1].Error) assert.Equal(s.t, fp1.Hash, results[0].Hash) assert.Equal(s.t, fp2.Hash, results[1].Hash) // Verify fingerprints were added to scenes foundScene1, err := s.client.findScene(scene1.UUID()) assert.NoError(s.t, err) assert.Len(s.t, foundScene1.Fingerprints, 2) // 1 original + 1 new foundScene2, err := s.client.findScene(scene2.UUID()) assert.NoError(s.t, err) assert.Len(s.t, foundScene2.Fingerprints, 2) // 1 original + 1 new } func (s *sceneTestRunner) testSubmitFingerprintsBatchMixedResults() { // Create one valid scene validScene, err := s.createTestScene(nil) assert.NoError(s.t, err) fp1 := s.generateSceneFingerprint(nil) fp2 := s.generateSceneFingerprint(nil) // Create a non-existent scene ID nonExistentID := uuid.Must(uuid.NewV4()) // Submit batch with mix of valid and invalid scene IDs results, err := s.client.submitFingerprints([]models.FingerprintBatchSubmission{ { SceneID: validScene.UUID(), Hash: fp1.Hash, Algorithm: fp1.Algorithm, Duration: fp1.Duration, }, { SceneID: nonExistentID, Hash: fp2.Hash, Algorithm: fp2.Algorithm, Duration: fp2.Duration, }, }) assert.NoError(s.t, err, "Error submitting fingerprints") assert.Len(s.t, results, 2) // First submission should succeed assert.Nil(s.t, results[0].Error) assert.Equal(s.t, fp1.Hash, results[0].Hash) // Second submission should fail (non-existent scene) assert.NotNil(s.t, results[1].Error) assert.Equal(s.t, fp2.Hash, results[1].Hash) // Verify valid scene got the fingerprint foundScene, err := s.client.findScene(validScene.UUID()) assert.NoError(s.t, err) assert.Len(s.t, foundScene.Fingerprints, 2) // 1 original + 1 new } func (s *sceneTestRunner) testSubmitFingerprintsBatchMaxLimit() { // Create a batch of 1001 fingerprints (exceeds limit) scene, err := s.createTestScene(nil) assert.NoError(s.t, err) submissions := make([]models.FingerprintBatchSubmission, 1001) for i := 0; i < 1001; i++ { fp := s.generateSceneFingerprint(nil) submissions[i] = models.FingerprintBatchSubmission{ SceneID: scene.UUID(), Hash: fp.Hash, Algorithm: fp.Algorithm, Duration: fp.Duration, } } // Should return an error _, err = s.client.submitFingerprints(submissions) assert.Error(s.t, err) assert.Contains(s.t, err.Error(), "1000") } func (s *sceneTestRunner) testFindScenesBySceneFingerprints() { // Enable phash distance matching for this test originalPHashDistance := config.GetPHashDistance() config.C.PHashDistance = 2 defer func() { config.C.PHashDistance = originalPHashDistance }() // Create a scene with multiple fingerprints (MD5, OSHASH, and PHASH) title := "Scene with Multiple Fingerprints for Scene Fingerprints Query" md5Fingerprint := s.generateSceneFingerprintWithAlgorithm(models.FingerprintAlgorithmMd5, nil) oshashFingerprint := s.generateSceneFingerprintWithAlgorithm(models.FingerprintAlgorithmOshash, nil) phashFingerprint := models.FingerprintEditInput{ Algorithm: models.FingerprintAlgorithmPhash, Hash: models.FingerprintHash(0x2), // Different from the other test Duration: 1234, UserIds: []uuid.UUID{}, } input := models.SceneCreateInput{ Title: &title, Date: "2020-03-02", Fingerprints: []models.FingerprintEditInput{ md5Fingerprint, oshashFingerprint, phashFingerprint, }, } createdScene, err := s.createTestScene(&input) assert.NoError(s.t, err) // Query with all three fingerprints as a single scene's fingerprints // This should return the scene ONCE, not three times queryFingerprints := [][]models.FingerprintQueryInput{ { { Algorithm: md5Fingerprint.Algorithm, Hash: md5Fingerprint.Hash, }, { Algorithm: oshashFingerprint.Algorithm, Hash: oshashFingerprint.Hash, }, { Algorithm: phashFingerprint.Algorithm, Hash: phashFingerprint.Hash, }, }, } results, err := s.client.findScenesBySceneFingerprints(queryFingerprints) assert.NoError(s.t, err) // Should return one array (one for each input set of fingerprints) assert.Equal(s.t, len(results), 1, "Should return one result set") // Within that array, the scene should only appear ONCE, not three times assert.Equal(s.t, len(results[0]), 1, "Scene should only be returned once, not duplicated for each fingerprint") assert.Equal(s.t, results[0][0].ID, createdScene.ID, "Returned scene should match the created scene") } func TestFindScenesBySceneFingerprints(t *testing.T) { pt := createSceneTestRunner(t) pt.testFindScenesBySceneFingerprints() } func (s *sceneTestRunner) testMoveFingerprintSubmissions() { // Create two scenes with fingerprints scene1, err := s.createTestScene(nil) assert.Nil(s.t, err) scene2, err := s.createTestScene(nil) assert.Nil(s.t, err) // Add additional fingerprints to scene1 via submission fp1 := s.generateSceneFingerprintWithAlgorithm(models.FingerprintAlgorithmOshash, nil) fp2 := s.generateSceneFingerprintWithAlgorithm(models.FingerprintAlgorithmPhash, nil) _, err = s.client.submitFingerprint(models.FingerprintSubmission{ SceneID: scene1.UUID(), Fingerprint: &models.FingerprintInput{ Hash: fp1.Hash, Algorithm: fp1.Algorithm, Duration: fp1.Duration, }, }) assert.Nil(s.t, err) _, err = s.client.submitFingerprint(models.FingerprintSubmission{ SceneID: scene1.UUID(), Fingerprint: &models.FingerprintInput{ Hash: fp2.Hash, Algorithm: fp2.Algorithm, Duration: fp2.Duration, }, }) assert.Nil(s.t, err) // Verify scene1 has the fingerprints updatedScene1, err := s.client.findScene(scene1.UUID()) assert.Nil(s.t, err) assert.True(s.t, len(updatedScene1.Fingerprints) >= 2) // Move the fingerprints from scene1 to scene2 moderateUser, err := s.createTestUser(nil, []models.RoleEnum{models.RoleEnumModerate}) assert.Nil(s.t, err) moderateRunner := createTestRunner(s.t, moderateUser, []models.RoleEnum{models.RoleEnumModerate}) _, err = moderateRunner.client.sceneMoveFingerprintSubmissions(models.MoveFingerprintSubmissionsInput{ Fingerprints: []models.FingerprintQueryInput{ {Hash: fp1.Hash, Algorithm: fp1.Algorithm}, {Hash: fp2.Hash, Algorithm: fp2.Algorithm}, }, SourceSceneID: scene1.UUID(), TargetSceneID: scene2.UUID(), }) fmt.Println(err) assert.Nil(s.t, err) // Verify scene1 no longer has these fingerprints updatedScene1, err = s.client.findScene(scene1.UUID()) assert.Nil(s.t, err) for _, fp := range updatedScene1.Fingerprints { assert.NotEqual(s.t, fp1.Hash, fp.Hash) assert.NotEqual(s.t, fp2.Hash, fp.Hash) } // Verify scene2 now has the fingerprints updatedScene2, err := s.client.findScene(scene2.UUID()) assert.Nil(s.t, err) foundFP1 := false foundFP2 := false for _, fp := range updatedScene2.Fingerprints { if fp.FingerprintHash() == fp1.Hash && fp.Algorithm == fp1.Algorithm { foundFP1 = true } if fp.FingerprintHash() == fp2.Hash && fp.Algorithm == fp2.Algorithm { foundFP2 = true } } assert.True(s.t, foundFP1, "Fingerprint 1 should be moved to scene2") assert.True(s.t, foundFP2, "Fingerprint 2 should be moved to scene2") } func (s *sceneTestRunner) testDeleteFingerprintSubmissions() { // Create a scene with fingerprints scene, err := s.createTestScene(nil) assert.Nil(s.t, err) // Add additional fingerprints via submission fp1 := s.generateSceneFingerprintWithAlgorithm(models.FingerprintAlgorithmOshash, nil) fp2 := s.generateSceneFingerprintWithAlgorithm(models.FingerprintAlgorithmPhash, nil) _, err = s.client.submitFingerprint(models.FingerprintSubmission{ SceneID: scene.UUID(), Fingerprint: &models.FingerprintInput{ Hash: fp1.Hash, Algorithm: fp1.Algorithm, Duration: fp1.Duration, }, }) assert.Nil(s.t, err) _, err = s.client.submitFingerprint(models.FingerprintSubmission{ SceneID: scene.UUID(), Fingerprint: &models.FingerprintInput{ Hash: fp2.Hash, Algorithm: fp2.Algorithm, Duration: fp2.Duration, }, }) assert.Nil(s.t, err) // Verify scene has the fingerprints updatedScene, err := s.client.findScene(scene.UUID()) assert.Nil(s.t, err) initialCount := len(updatedScene.Fingerprints) assert.True(s.t, initialCount >= 2) // Delete the fingerprints moderateUser, err := s.createTestUser(nil, []models.RoleEnum{models.RoleEnumModerate}) assert.Nil(s.t, err) moderateRunner := createTestRunner(s.t, moderateUser, []models.RoleEnum{models.RoleEnumModerate}) _, err = moderateRunner.client.sceneDeleteFingerprintSubmissions(models.DeleteFingerprintSubmissionsInput{ Fingerprints: []models.FingerprintQueryInput{ {Hash: fp1.Hash, Algorithm: fp1.Algorithm}, {Hash: fp2.Hash, Algorithm: fp2.Algorithm}, }, SceneID: scene.UUID(), }) assert.Nil(s.t, err) // Verify scene no longer has these fingerprints updatedScene, err = s.client.findScene(scene.UUID()) assert.Nil(s.t, err) for _, fp := range updatedScene.Fingerprints { assert.NotEqual(s.t, fp1.Hash, fp.Hash, "Fingerprint 1 should be deleted") assert.NotEqual(s.t, fp2.Hash, fp.Hash, "Fingerprint 2 should be deleted") } assert.Equal(s.t, initialCount-2, len(updatedScene.Fingerprints), "Should have 2 fewer fingerprints") } func TestMoveFingerprintSubmissions(t *testing.T) { pt := createSceneTestRunner(t) pt.testMoveFingerprintSubmissions() } func TestDeleteFingerprintSubmissions(t *testing.T) { pt := createSceneTestRunner(t) pt.testDeleteFingerprintSubmissions() } func (s *sceneTestRunner) testFindScenesBySceneFingerprintsMultipleMatches() { // Create multiple scenes with the same OSHASH to test that all are returned // Using OSHASH instead of phash to avoid distance matching complexity sharedHash := models.FingerprintHash(0x1234567890abcdef) title1 := "Scene 1 with Shared Hash" oshashFingerprint1 := models.FingerprintEditInput{ Algorithm: models.FingerprintAlgorithmOshash, Hash: sharedHash, Duration: 1234, UserIds: []uuid.UUID{}, } input1 := models.SceneCreateInput{ Title: &title1, Date: "2020-03-02", Fingerprints: []models.FingerprintEditInput{ oshashFingerprint1, }, } createdScene1, err := s.createTestScene(&input1) assert.NoError(s.t, err) title2 := "Scene 2 with Shared Hash" oshashFingerprint2 := models.FingerprintEditInput{ Algorithm: models.FingerprintAlgorithmOshash, Hash: sharedHash, Duration: 1235, UserIds: []uuid.UUID{}, } input2 := models.SceneCreateInput{ Title: &title2, Date: "2020-03-03", Fingerprints: []models.FingerprintEditInput{ oshashFingerprint2, }, } createdScene2, err := s.createTestScene(&input2) assert.NoError(s.t, err) title3 := "Scene 3 with Shared Hash" oshashFingerprint3 := models.FingerprintEditInput{ Algorithm: models.FingerprintAlgorithmOshash, Hash: sharedHash, Duration: 1236, UserIds: []uuid.UUID{}, } input3 := models.SceneCreateInput{ Title: &title3, Date: "2020-03-04", Fingerprints: []models.FingerprintEditInput{ oshashFingerprint3, }, } createdScene3, err := s.createTestScene(&input3) assert.NoError(s.t, err) // Query with the shared hash - should return ALL three scenes queryFingerprints := [][]models.FingerprintQueryInput{ { { Algorithm: models.FingerprintAlgorithmOshash, Hash: sharedHash, }, }, } results, err := s.client.findScenesBySceneFingerprints(queryFingerprints) assert.NoError(s.t, err) // Should return one array (one for each input set of fingerprints) assert.Equal(s.t, 1, len(results), "Should return one result set") // Within that array, all three scenes should be returned assert.Equal(s.t, 3, len(results[0]), "All three scenes with the same hash should be returned") // Verify all three scene IDs are present returnedIDs := make(map[string]bool) for _, scene := range results[0] { returnedIDs[scene.ID] = true } assert.True(s.t, returnedIDs[createdScene1.ID], "Scene 1 should be in results") assert.True(s.t, returnedIDs[createdScene2.ID], "Scene 2 should be in results") assert.True(s.t, returnedIDs[createdScene3.ID], "Scene 3 should be in results") } func TestFindScenesBySceneFingerprintsMultipleMatches(t *testing.T) { pt := createSceneTestRunner(t) pt.testFindScenesBySceneFingerprintsMultipleMatches() } ================================================ FILE: internal/api/search_integration_test.go ================================================ //go:build integration package api_test import ( "testing" "github.com/stashapp/stash-box/internal/models" "github.com/stretchr/testify/assert" ) type searchTestRunner struct { testRunner } func createSearchTestRunner(t *testing.T) *searchTestRunner { return &searchTestRunner{ testRunner: *asModify(t), } } func (s *searchTestRunner) testSearchPerformerByTerm() { createdPerformer, err := s.createTestPerformer(nil) assert.NoError(s.t, err) result, err := s.resolver.Query().SearchPerformers(s.ctx, createdPerformer.Name, nil, nil, nil, nil) assert.NoError(s.t, err, "Error finding performer") performers := result.SearchResults.Performers // ensure returned performer is not nil assert.True(s.t, len(performers) > 0, "Did not find performer by name search") // ensure values were set assert.Equal(s.t, createdPerformer.UUID(), performers[0].ID) } func (s *searchTestRunner) testSearchPerformerByID() { createdPerformer, err := s.createTestPerformer(nil) assert.NoError(s.t, err) result, err := s.resolver.Query().SearchPerformers(s.ctx, " "+createdPerformer.ID, nil, nil, nil, nil) assert.NoError(s.t, err, "Error finding performer") performers := result.SearchResults.Performers // ensure returned performer is not nil assert.True(s.t, len(performers) > 0, "Did not find performer by name search") // ensure values were set assert.Equal(s.t, createdPerformer.UUID(), performers[0].ID) } func (s *searchTestRunner) testSearchPerformerByNonExistentID() { // Search for a non-existent performer ID should return empty result, not error nonExistentID := "00000000-0000-0000-0000-000000000000" result, err := s.resolver.Query().SearchPerformers(s.ctx, nonExistentID, nil, nil, nil, nil) assert.NoError(s.t, err, "Should not error when performer not found") assert.Equal(s.t, 0, len(result.SearchResults.Performers), "Should return empty result for non-existent ID") } func (s *searchTestRunner) testSearchSceneByTerm() { createdStudio, err := s.createTestStudio(nil) assert.NoError(s.t, err) studioID := createdStudio.UUID() title := "scene search title" date := "2019-02-03" input := models.SceneCreateInput{ Title: &title, Date: date, StudioID: &studioID, } createdScene, err := s.createTestScene(&input) assert.NoError(s.t, err) result, err := s.resolver.Query().SearchScenes(s.ctx, *createdScene.Title+" "+*createdScene.Date, nil, nil, nil) assert.NoError(s.t, err, "Error finding scene") scenes := result.SearchResults.Scenes assert.True(s.t, len(scenes) > 0, "Did not find scene by search") // ensure correct scene assert.Equal(s.t, createdScene.UUID(), scenes[0].ID) } func (s *searchTestRunner) testSearchSceneByID() { createdScene, err := s.createTestScene(nil) assert.NoError(s.t, err) result, err := s.resolver.Query().SearchScenes(s.ctx, " "+createdScene.ID, nil, nil, nil) assert.NoError(s.t, err, "Error finding scene") scenes := result.SearchResults.Scenes // ensure a scene is returned assert.True(s.t, len(scenes) > 0, "Did not find scene by id search") // ensure correct scene assert.Equal(s.t, createdScene.UUID(), scenes[0].ID) } func (s *searchTestRunner) testSearchTagByTerm() { createdTag, err := s.createTestTag(nil) assert.NoError(s.t, err) tags, err := s.resolver.Query().SearchTag(s.ctx, createdTag.Name, nil) assert.NoError(s.t, err, "Error finding tag") // ensure returned tag is not nil assert.True(s.t, len(tags) > 0, "Did not find tag by name search") // ensure values were set assert.Equal(s.t, createdTag.UUID(), tags[0].ID) } func (s *searchTestRunner) testSearchTagByID() { createdTag, err := s.createTestTag(nil) assert.NoError(s.t, err) tags, err := s.resolver.Query().SearchTag(s.ctx, " "+createdTag.ID, nil) assert.NoError(s.t, err, "Error finding tag") // ensure returned tag is not nil assert.True(s.t, len(tags) > 0, "Did not find tag by name search") // ensure values were set assert.Equal(s.t, createdTag.UUID(), tags[0].ID) } func TestSearchPerformerByTerm(t *testing.T) { pt := createSearchTestRunner(t) pt.testSearchPerformerByTerm() } func TestSearchPerformerByID(t *testing.T) { pt := createSearchTestRunner(t) pt.testSearchPerformerByID() } func TestSearchPerformerByNonExistentID(t *testing.T) { pt := createSearchTestRunner(t) pt.testSearchPerformerByNonExistentID() } func TestSearchSceneByTerm(t *testing.T) { pt := createSearchTestRunner(t) pt.testSearchSceneByTerm() } func TestSearchSceneByID(t *testing.T) { pt := createSearchTestRunner(t) pt.testSearchSceneByID() } func TestSearchTagByTerm(t *testing.T) { pt := createSearchTestRunner(t) pt.testSearchTagByTerm() } func TestSearchTagByID(t *testing.T) { pt := createSearchTestRunner(t) pt.testSearchTagByID() } func (s *searchTestRunner) testSearchPerformerFacets() { // Create performers with different genders female := models.GenderEnumFemale male := models.GenderEnumMale input1 := models.PerformerCreateInput{ Name: "Test Facet Performer Female", Gender: &female, } _, err := s.createTestPerformer(&input1) assert.NoError(s.t, err) input2 := models.PerformerCreateInput{ Name: "Test Facet Performer Male", Gender: &male, } _, err = s.createTestPerformer(&input2) assert.NoError(s.t, err) // Search and check facets result, err := s.resolver.Query().SearchPerformers(s.ctx, "Test Facet Performer", nil, nil, nil, nil) assert.NoError(s.t, err, "Error searching performers") assert.True(s.t, len(result.SearchResults.Performers) >= 2, "Should find at least 2 performers") // Check facets are present facets := result.SearchResults.Facets assert.NotNil(s.t, facets, "Facets should be present for search results") } func (s *searchTestRunner) testQueryPerformerNoFacets() { // queryPerformers should return nil facets input := models.PerformerQueryInput{ Page: 1, PerPage: 10, } queryResult, err := s.resolver.Query().QueryPerformers(s.ctx, input) assert.NoError(s.t, err) // Get facets via resolver facets, err := s.resolver.QueryPerformersResultType().Facets(s.ctx, queryResult) assert.NoError(s.t, err) assert.Nil(s.t, facets, "Facets should be nil for queryPerformers") } func TestSearchPerformerFacets(t *testing.T) { pt := createSearchTestRunner(t) pt.testSearchPerformerFacets() } func TestQueryPerformerNoFacets(t *testing.T) { pt := createSearchTestRunner(t) pt.testQueryPerformerNoFacets() } ================================================ FILE: internal/api/server.go ================================================ package api import ( "context" "crypto/tls" "embed" "errors" "fmt" "net/http" "net/http/pprof" "os" "runtime/debug" "strconv" "strings" "github.com/gofrs/uuid" "github.com/klauspost/compress/flate" "github.com/vektah/gqlparser/v2/gqlerror" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" "github.com/ravilushqa/otelgqlgen" "github.com/99designs/gqlgen/graphql" gqlHandler "github.com/99designs/gqlgen/graphql/handler" gqlExtension "github.com/99designs/gqlgen/graphql/handler/extension" gqlTransport "github.com/99designs/gqlgen/graphql/handler/transport" gqlPlayground "github.com/99designs/gqlgen/graphql/playground" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" "github.com/riandyrn/otelchi" "github.com/rs/cors" "github.com/stashapp/stash-box/internal/auth" "github.com/stashapp/stash-box/internal/autocert" "github.com/stashapp/stash-box/internal/config" "github.com/stashapp/stash-box/internal/dataloader" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/internal/service" "github.com/stashapp/stash-box/internal/service/user" "github.com/stashapp/stash-box/pkg/logger" ) var version string var buildstamp string var githash string var buildtype string const APIKeyHeader = "ApiKey" func getUserAndRoles(ctx context.Context, fac service.Factory, userID string) (*models.User, []models.RoleEnum, error) { if userID == "" { return nil, nil, nil } id, err := uuid.FromString(userID) if err != nil { return nil, nil, err } u, err := fac.User().FindByID(ctx, id) if err != nil { return nil, nil, err } roles, err := fac.User().GetRoles(ctx, id) if err != nil { return nil, nil, err } return u, roles, nil } func authenticateHandler(fac service.Factory) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() // translate api key into current user, if present userID := "" apiKey := r.Header.Get(APIKeyHeader) var err error if apiKey != "" { userID, err = user.GetUserIDFromAPIKey(apiKey) } else { // handle session userID, err = getSessionUserID(w, r) } var u *models.User var roles []models.RoleEnum if err == nil { u, roles, err = getUserAndRoles(ctx, fac, userID) } if err != nil { w.WriteHeader(http.StatusInternalServerError) _, err = w.Write([]byte(err.Error())) if err != nil { logger.Error(err) } return } // ensure api key of the user matches the passed one if apiKey != "" && u != nil && u.APIKey != apiKey { w.WriteHeader(http.StatusUnauthorized) return } // TODO - increment api key counters ctx = context.WithValue(ctx, auth.ContextUser, u) ctx = context.WithValue(ctx, auth.ContextRoles, roles) span := trace.SpanFromContext(ctx) if span.SpanContext().IsValid() && u != nil { span.SetAttributes( attribute.String("user.id", u.ID.String()), attribute.String("user.name", u.Name), ) } r = r.WithContext(ctx) next.ServeHTTP(w, r) }) } } func redirect(w http.ResponseWriter, req *http.Request) { target := "https://" + req.Host + req.URL.Path if len(req.URL.RawQuery) > 0 { target += "?" + req.URL.RawQuery } http.Redirect(w, req, target, http.StatusPermanentRedirect) } func Start(fac service.Factory, ui embed.FS) { r := chi.NewRouter() r.Use(otelchi.Middleware("", otelchi.WithChiRoutes(r))) var corsConfig *cors.Cors if config.GetIsProduction() { corsConfig = cors.AllowAll() } else { corsConfig = cors.New(cors.Options{ AllowOriginFunc: func(origin string) bool { return true }, AllowCredentials: true, AllowedHeaders: []string{"*"}, }) } r.Use(corsConfig.Handler) r.Use(authenticateHandler(fac)) r.Use(middleware.Recoverer) compressor := middleware.NewCompressor(flate.DefaultCompression) r.Use(compressor.Handler) r.Use(middleware.StripSlashes) r.Use(BaseURLMiddleware) recoverFunc := func(ctx context.Context, err interface{}) error { logger.Error(err) debug.PrintStack() message := fmt.Sprintf("Internal system error. Error <%v>", err) return errors.New(message) } gqlConfig := models.Config{ Resolvers: NewResolver(fac), Directives: models.DirectiveRoot{ IsUserOwner: IsUserOwnerDirective, HasRole: HasRoleDirective, }, } gqlSrv := gqlHandler.New(models.NewExecutableSchema(gqlConfig)) gqlSrv.SetRecoverFunc(recoverFunc) gqlSrv.AddTransport(gqlTransport.Options{}) gqlSrv.AddTransport(gqlTransport.GET{}) gqlSrv.AddTransport(gqlTransport.POST{}) gqlSrv.AddTransport(gqlTransport.MultipartForm{}) gqlSrv.Use(gqlExtension.Introspection{}) gqlSrv.Use(otelgqlgen.Middleware(otelgqlgen.WithCreateSpanFromFields(func(fieldCtx *graphql.FieldContext) bool { return fieldCtx.IsResolver }))) gqlSrv.SetErrorPresenter(func(ctx context.Context, e error) *gqlerror.Error { err := graphql.DefaultErrorPresenter(ctx, e) // Get username from context if available username := "anonymous" if user := auth.GetCurrentUser(ctx); user != nil { username = user.Name } // Log the error at debug level with username logger.Debugf("GraphQL error [user: %s]: %v", username, err) return err }) r.Handle("/graphql", dataloader.Middleware(fac)(gqlSrv)) if !config.GetIsProduction() { r.Handle("/playground", gqlPlayground.Handler("GraphQL playground", "/graphql")) } r.Mount("/", rootRoutes{ui: ui}.Routes(fac)) if config.GetProfilerPort() != nil { go func() { mux := http.NewServeMux() mux.HandleFunc("/", pprof.Index) mux.HandleFunc("/cmdline", pprof.Cmdline) mux.HandleFunc("/profile", pprof.Profile) mux.HandleFunc("/symbol", pprof.Symbol) mux.HandleFunc("/trace", pprof.Trace) mux.Handle("/allocs", pprof.Handler("allocs")) mux.Handle("/block", pprof.Handler("block")) mux.Handle("/goroutine", pprof.Handler("goroutine")) mux.Handle("/heap", pprof.Handler("heap")) mux.Handle("/mutex", pprof.Handler("mutex")) mux.Handle("/threadcreate", pprof.Handler("threadcreate")) logger.Infof("profiler is running at http://localhost:%d/", *config.GetProfilerPort()) logger.Fatal(http.ListenAndServe(":"+strconv.Itoa(*config.GetProfilerPort()), mux)) }() } address := config.GetHost() + ":" + strconv.Itoa(config.GetPort()) // Priority 1: Autocert (Let's Encrypt) if tlsConfig := autocert.Init(); tlsConfig != nil { httpsServer := &http.Server{ Addr: address, Handler: r, TLSConfig: tlsConfig, } // Start HTTP server for ACME HTTP-01 challenges on port 80 // Non-challenge requests are redirected to HTTPS go func() { logger.Infof("Starting HTTP server on %s:80 for ACME challenges", config.GetHost()) if err := http.ListenAndServe(config.GetHost()+":80", autocert.HTTPHandler(http.HandlerFunc(redirect))); err != nil { logger.Errorf("HTTP server error: %v", err) } }() go func() { printVersion() logger.Infof("stash-box is running on HTTPS (autocert) at https://%s/", address) logger.Fatal(httpsServer.ListenAndServeTLS("", "")) }() return } // Priority 2: File-based TLS if tlsConfig := makeTLSConfig(); tlsConfig != nil { httpsServer := &http.Server{ Addr: address, Handler: r, TLSConfig: tlsConfig, } if config.GetHTTPUpgrade() { go func() { logger.Fatal(http.ListenAndServe(config.GetHost()+":80", http.HandlerFunc(redirect))) }() } go func() { printVersion() logger.Infof("stash-box is running on HTTPS at https://%s/", address) logger.Fatal(httpsServer.ListenAndServeTLS("", "")) }() return } // Priority 3: HTTP only server := &http.Server{ Addr: address, Handler: r, } go func() { printVersion() logger.Infof("stash-box is running on HTTP at http://%s/", address) logger.Fatal(server.ListenAndServe()) }() } func printVersion() { versionString := version if buildtype != "OFFICIAL" { versionString += " (" + githash + ")" } fmt.Printf("stash-box version: %s - %s\n", versionString, buildstamp) } func GetVersion() (string, string, string) { return version, githash, buildstamp } func makeTLSConfig() *tls.Config { cert, err := os.ReadFile(config.GetSSLCert()) if err != nil { return nil } key, err := os.ReadFile(config.GetSSLKey()) if err != nil { return nil } certs := make([]tls.Certificate, 1) certs[0], err = tls.X509KeyPair(cert, key) if err != nil { return nil } tlsConfig := &tls.Config{ Certificates: certs, MinVersion: tls.VersionTLS13, } return tlsConfig } type contextKey struct { name string } var ( BaseURLCtxKey = &contextKey{"BaseURL"} ) func BaseURLMiddleware(next http.Handler) http.Handler { fn := func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() var scheme string if strings.Compare("https", r.URL.Scheme) == 0 || r.Proto == "HTTP/2.0" || r.Header.Get("X-Forwarded-Proto") == "https" { scheme = "https" } else { scheme = "http" } baseURL := scheme + "://" + r.Host r = r.WithContext(context.WithValue(ctx, BaseURLCtxKey, baseURL)) next.ServeHTTP(w, r) } return http.HandlerFunc(fn) } ================================================ FILE: internal/api/session.go ================================================ package api import ( "errors" "net/http" "github.com/stashapp/stash-box/internal/config" "github.com/stashapp/stash-box/internal/service" "github.com/stashapp/stash-box/internal/service/user" "github.com/gorilla/sessions" ) const cookieName = "stashbox" const usernameFormKey = "username" const passwordFormKey = "password" const userIDKey = "userID" const maxCookieAge = 60 * 60 * 24 * 30 // 1 month var sessionStore *sessions.CookieStore func InitializeSession() { sessionStore = sessions.NewCookieStore(config.GetSessionStoreKey()) } func handleLogin(fac service.Factory) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, r *http.Request) { newSession, err := sessionStore.Get(r, cookieName) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } username := r.FormValue(usernameFormKey) password := r.FormValue(passwordFormKey) // authenticate the user userID, err := fac.User().Authenticate(r.Context(), username, password) if errors.Is(err, user.ErrAccessDenied) { http.Error(w, err.Error(), http.StatusUnauthorized) return } else if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } newSession.Values[userIDKey] = userID newSession.Options.MaxAge = maxCookieAge newSession.Options.HttpOnly = true if config.GetIsProduction() { newSession.Options.Secure = true } else { newSession.Options.Secure = false newSession.Options.SameSite = http.SameSiteLaxMode } err = newSession.Save(r, w) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } } } func handleLogout(w http.ResponseWriter, r *http.Request) { session, err := sessionStore.Get(r, cookieName) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } delete(session.Values, userIDKey) session.Options.MaxAge = -1 session.Options.HttpOnly = true if config.GetIsProduction() { session.Options.Secure = true } else { session.Options.Secure = false session.Options.SameSite = http.SameSiteLaxMode } err = session.Save(r, w) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } // Redirect to home page after successful logout http.Redirect(w, r, "/", http.StatusFound) } func getSessionUserID(w http.ResponseWriter, r *http.Request) (string, error) { session, err := sessionStore.Get(r, cookieName) if err != nil { session.Options.MaxAge = -1 if err = session.Save(r, w); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } return "", nil } if !session.IsNew { userIDInt := session.Values[userIDKey] userID, _ := userIDInt.(string) // refresh the cookie err = session.Save(r, w) if err != nil { return "", err } return userID, nil } return "", nil } ================================================ FILE: internal/api/site_integration_test.go ================================================ //go:build integration package api_test import ( "testing" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" "github.com/stretchr/testify/assert" ) type siteTestRunner struct { testRunner } func createSiteTestRunner(t *testing.T) *siteTestRunner { return &siteTestRunner{ testRunner: *asAdmin(t), } } func (s *siteTestRunner) testCreateSite() { description := "Test site description" url := "https://example.com" regex := `^https://example\.com/.*$` input := models.SiteCreateInput{ Name: s.generateSiteName(), Description: &description, URL: &url, Regex: ®ex, ValidTypes: []models.ValidSiteTypeEnum{models.ValidSiteTypeEnumScene, models.ValidSiteTypeEnumPerformer}, } site, err := s.resolver.Mutation().SiteCreate(s.ctx, input) assert.NoError(s.t, err, "Error creating site") s.verifyCreatedSite(input, site) } func (s *siteTestRunner) verifyCreatedSite(input models.SiteCreateInput, site *models.Site) { // ensure basic attributes are set correctly assert.Equal(s.t, input.Name, site.Name) assert.True(s.t, site.ID != uuid.Nil, "Expected created site id to be non-zero") // verify optional fields if input.Description != nil { assert.NotNil(s.t, site.Description, "Expected description to be set") assert.Equal(s.t, *input.Description, *site.Description) } if input.URL != nil { assert.NotNil(s.t, site.URL, "Expected URL to be set") assert.Equal(s.t, *input.URL, *site.URL) } if input.Regex != nil { assert.NotNil(s.t, site.Regex, "Expected regex to be set") assert.Equal(s.t, *input.Regex, *site.Regex) } // verify valid types assert.Equal(s.t, len(input.ValidTypes), len(site.ValidTypes)) } func (s *siteTestRunner) testFindSiteById() { createdSite, err := s.createTestSite(nil) assert.NoError(s.t, err) siteID := createdSite.ID site, err := s.client.findSite(siteID) assert.NoError(s.t, err, "Error finding site") // ensure returned site is not nil assert.NotNil(s.t, site, "Did not find site by id") // ensure values were set assert.Equal(s.t, createdSite.Name, site.Name) } func (s *siteTestRunner) testQuerySites() { // Create multiple test sites site1, err := s.createTestSite(nil) assert.NoError(s.t, err) site2, err := s.createTestSite(nil) assert.NoError(s.t, err) result, err := s.client.querySites() assert.NoError(s.t, err, "Error querying sites") // ensure we have at least the sites we created assert.True(s.t, len(result.Sites) >= 2, "Expected at least 2 sites in query result") // verify our created sites are in the results found1 := false found2 := false for _, site := range result.Sites { if site.ID == site1.ID.String() { found1 = true } if site.ID == site2.ID.String() { found2 = true } } assert.True(s.t, found1, "Created site 1 not found in query results") assert.True(s.t, found2, "Created site 2 not found in query results") } func (s *siteTestRunner) testUpdateSite() { createdSite, err := s.createTestSite(nil) assert.NoError(s.t, err) siteID := createdSite.ID newDescription := "Updated description" newURL := "https://updated.com" newName := "Updated " + createdSite.Name updateInput := models.SiteUpdateInput{ ID: siteID, Name: newName, Description: &newDescription, URL: &newURL, ValidTypes: []models.ValidSiteTypeEnum{models.ValidSiteTypeEnumScene}, } updatedSite, err := s.client.updateSite(updateInput) assert.NoError(s.t, err, "Error updating site") s.verifyUpdatedSite(updateInput, updatedSite) } func (s *siteTestRunner) verifyUpdatedSite(input models.SiteUpdateInput, site *siteOutput) { // ensure ID matches assert.Equal(s.t, input.ID.String(), site.ID) // verify updated fields assert.Equal(s.t, input.Name, site.Name) if input.Description != nil { assert.NotNil(s.t, site.Description, "Expected description to be set") assert.Equal(s.t, *input.Description, *site.Description) } if input.URL != nil { assert.NotNil(s.t, site.URL, "Expected URL to be set") assert.Equal(s.t, *input.URL, *site.URL) } } func (s *siteTestRunner) testDestroySite() { createdSite, err := s.createTestSite(nil) assert.NoError(s.t, err) siteID := createdSite.ID destroyed, err := s.client.destroySite(models.SiteDestroyInput{ ID: siteID, }) assert.NoError(s.t, err, "Error destroying site") assert.True(s.t, destroyed, "Site was not destroyed") // ensure cannot find site foundSite, err := s.client.findSite(siteID) assert.NoError(s.t, err, "Error finding site after destroying") assert.Nil(s.t, foundSite, "Found site after destruction") } func TestCreateSite(t *testing.T) { st := createSiteTestRunner(t) st.testCreateSite() } func TestFindSiteById(t *testing.T) { st := createSiteTestRunner(t) st.testFindSiteById() } func TestQuerySites(t *testing.T) { st := createSiteTestRunner(t) st.testQuerySites() } func TestUpdateSite(t *testing.T) { st := createSiteTestRunner(t) st.testUpdateSite() } func TestDestroySite(t *testing.T) { st := createSiteTestRunner(t) st.testDestroySite() } ================================================ FILE: internal/api/studio_edit_integration_test.go ================================================ //go:build integration package api_test import ( "fmt" "testing" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" "github.com/stretchr/testify/assert" ) type studioEditTestRunner struct { testRunner } func createStudioEditTestRunner(t *testing.T) *studioEditTestRunner { return &studioEditTestRunner{ testRunner: *asAdmin(t), } } func (s *studioEditTestRunner) testCreateStudioEdit() { parentStudio, err := s.createTestStudio(nil) assert.NoError(s.t, err) parentID := parentStudio.UUID() name := "Name" studioEditDetailsInput := models.StudioEditDetailsInput{ Name: &name, ParentID: &parentID, } edit, err := s.createTestStudioEdit(models.OperationEnumCreate, &studioEditDetailsInput, nil) assert.NoError(s.t, err) s.verifyCreatedStudioEdit(studioEditDetailsInput, edit) } func (s *studioEditTestRunner) verifyCreatedStudioEdit(input models.StudioEditDetailsInput, edit *models.Edit) { r := s.resolver.Edit() assert.True(s.t, edit.ID != uuid.Nil, "Expected created edit id to be non-zero") details, _ := r.Details(s.ctx, edit) studioDetails := details.(*models.StudioEdit) s.verifyEditOperation(models.OperationEnumCreate.String(), edit) s.verifyEditStatus(models.VoteStatusEnumPending.String(), edit) s.verifyEditTargetType(models.TargetTypeEnumStudio.String(), edit) s.verifyEditApplication(false, edit) // ensure basic attributes are set correctly assert.Equal(s.t, *input.Name, *studioDetails.Name) assert.Equal(s.t, *input.ParentID, *studioDetails.ParentID) } func (s *studioEditTestRunner) testFindEditById() { createdEdit, err := s.createTestStudioEdit(models.OperationEnumCreate, nil, nil) assert.NoError(s.t, err) edit, err := s.resolver.Query().FindEdit(s.ctx, createdEdit.ID) assert.NoError(s.t, err, "Error finding edit") // ensure returned studio is not nil assert.NotNil(s.t, edit, "Did not find edit by id") } func (s *studioEditTestRunner) testModifyStudioEdit() { existingParentStudio, err := s.createTestStudio(nil) assert.NoError(s.t, err) existingParentID := existingParentStudio.UUID() existingName := "studioName" studioCreateInput := models.StudioCreateInput{ Name: existingName, ParentID: &existingParentID, } createdStudio, err := s.createTestStudio(&studioCreateInput) assert.NoError(s.t, err) newParent, err := s.createTestStudio(nil) assert.NoError(s.t, err) newParentID := newParent.UUID() newName := "newName" site, err := s.createTestSite(nil) assert.NoError(s.t, err) url := models.URL{ URL: "http://example.org", SiteID: site.ID, } studioEditDetailsInput := models.StudioEditDetailsInput{ Name: &newName, ParentID: &newParentID, Urls: []models.URL{url}, } id := createdStudio.UUID() editInput := models.EditInput{ Operation: models.OperationEnumModify, ID: &id, } createdUpdateEdit, err := s.createTestStudioEdit(models.OperationEnumModify, &studioEditDetailsInput, &editInput) assert.NoError(s.t, err) s.verifyUpdatedStudioEdit(createdStudio, studioEditDetailsInput, createdUpdateEdit) } func (s *studioEditTestRunner) verifyUpdatedStudioEdit(originalStudio *studioOutput, input models.StudioEditDetailsInput, edit *models.Edit) { studioDetails := s.getEditStudioDetails(edit) s.verifyEditOperation(models.OperationEnumModify.String(), edit) s.verifyEditStatus(models.VoteStatusEnumPending.String(), edit) s.verifyEditTargetType(models.TargetTypeEnumStudio.String(), edit) s.verifyEditApplication(false, edit) // ensure basic attributes are set correctly assert.Equal(s.t, *input.Name, *studioDetails.Name) assert.Equal(s.t, *input.ParentID, *studioDetails.ParentID) assert.Equal(s.t, input.Urls, studioDetails.AddedUrls) } func (s *studioEditTestRunner) testDestroyStudioEdit() { createdStudio, err := s.createTestStudio(nil) assert.NoError(s.t, err) studioID := createdStudio.UUID() studioEditDetailsInput := models.StudioEditDetailsInput{} editInput := models.EditInput{ Operation: models.OperationEnumDestroy, ID: &studioID, } destroyEdit, err := s.createTestStudioEdit(models.OperationEnumDestroy, &studioEditDetailsInput, &editInput) assert.NoError(s.t, err) s.verifyDestroyStudioEdit(studioID, destroyEdit) } func (s *studioEditTestRunner) verifyDestroyStudioEdit(studioID uuid.UUID, edit *models.Edit) { s.verifyEditOperation(models.OperationEnumDestroy.String(), edit) s.verifyEditStatus(models.VoteStatusEnumPending.String(), edit) s.verifyEditTargetType(models.TargetTypeEnumStudio.String(), edit) s.verifyEditApplication(false, edit) editTarget := s.getEditStudioTarget(edit) assert.Equal(s.t, studioID, editTarget.ID) } func (s *studioEditTestRunner) testMergeStudioEdit() { existingName := "studioName2" studioCreateInput := models.StudioCreateInput{ Name: existingName, } createdPrimaryStudio, err := s.createTestStudio(&studioCreateInput) assert.NoError(s.t, err) createdMergeStudio, err := s.createTestStudio(nil) newName := "newName2" studioEditDetailsInput := models.StudioEditDetailsInput{ Name: &newName, } id := createdPrimaryStudio.UUID() mergeSources := []uuid.UUID{createdMergeStudio.UUID()} editInput := models.EditInput{ Operation: models.OperationEnumMerge, ID: &id, MergeSourceIds: mergeSources, } createdMergeEdit, err := s.createTestStudioEdit(models.OperationEnumMerge, &studioEditDetailsInput, &editInput) assert.NoError(s.t, err) s.verifyMergeStudioEdit(createdPrimaryStudio, studioEditDetailsInput, createdMergeEdit, mergeSources) } func (s *studioEditTestRunner) verifyMergeStudioEdit(originalStudio *studioOutput, input models.StudioEditDetailsInput, edit *models.Edit, inputMergeSources []uuid.UUID) { studioDetails := s.getEditStudioDetails(edit) s.verifyEditOperation(models.OperationEnumMerge.String(), edit) s.verifyEditStatus(models.VoteStatusEnumPending.String(), edit) s.verifyEditTargetType(models.TargetTypeEnumStudio.String(), edit) s.verifyEditApplication(false, edit) // ensure basic attributes are set correctly assert.Equal(s.t, *input.Name, *studioDetails.Name) var mergeSources []uuid.UUID merges, _ := s.resolver.Edit().MergeSources(s.ctx, edit) for i := range merges { merge := merges[i].(*models.Studio) mergeSources = append(mergeSources, merge.ID) } assert.Equal(s.t, inputMergeSources, mergeSources) } func (s *studioEditTestRunner) testApplyCreateStudioEdit() { name := "Name" parent, err := s.createTestStudio(nil) assert.NoError(s.t, err) parentID := parent.UUID() studioEditDetailsInput := models.StudioEditDetailsInput{ Name: &name, ParentID: &parentID, } edit, err := s.createTestStudioEdit(models.OperationEnumCreate, &studioEditDetailsInput, nil) assert.NoError(s.t, err) appliedEdit, err := s.applyEdit(edit.ID) assert.NoError(s.t, err) s.verifyAppliedStudioCreateEdit(studioEditDetailsInput, appliedEdit) } func (s *studioEditTestRunner) verifyAppliedStudioCreateEdit(input models.StudioEditDetailsInput, edit *models.Edit) { assert.True(s.t, edit.ID != uuid.Nil, "Expected created edit id to be non-zero") s.verifyEditOperation(models.OperationEnumCreate.String(), edit) s.verifyEditStatus(models.VoteStatusEnumImmediateAccepted.String(), edit) s.verifyEditTargetType(models.TargetTypeEnumStudio.String(), edit) s.verifyEditApplication(true, edit) studio := s.getEditStudioTarget(edit) // ensure basic attributes are set correctly assert.Equal(s.t, *input.Name, studio.Name) assert.Equal(s.t, *input.ParentID, studio.ParentStudioID.UUID) } func (s *studioEditTestRunner) testApplyModifyStudioEdit() { existingName := "studioName3" site, err := s.createTestSite(nil) assert.NoError(s.t, err) studioCreateInput := models.StudioCreateInput{ Name: existingName, Urls: []models.URL{{ URL: "http://example.org/old", SiteID: site.ID, }}, } createdStudio, err := s.createTestStudio(&studioCreateInput) assert.NoError(s.t, err) newName := "newName3" newParent, err := s.createTestStudio(nil) assert.NoError(s.t, err) newParentID := newParent.UUID() newUrl := models.URL{ URL: "http://example.org/new", SiteID: site.ID, } studioEditDetailsInput := models.StudioEditDetailsInput{ Name: &newName, ParentID: &newParentID, Urls: []models.URL{newUrl}, } id := createdStudio.UUID() editInput := models.EditInput{ Operation: models.OperationEnumModify, ID: &id, } createdUpdateEdit, err := s.createTestStudioEdit(models.OperationEnumModify, &studioEditDetailsInput, &editInput) assert.NoError(s.t, err) appliedEdit, err := s.applyEdit(createdUpdateEdit.ID) assert.NoError(s.t, err) modifiedStudio, err := s.resolver.Query().FindStudio(s.ctx, &id, nil) assert.NoError(s.t, err) s.verifyApplyModifyStudioEdit(studioEditDetailsInput, modifiedStudio, appliedEdit) } func (s *studioEditTestRunner) verifyApplyModifyStudioEdit(input models.StudioEditDetailsInput, updatedStudio *models.Studio, edit *models.Edit) { s.verifyEditOperation(models.OperationEnumModify.String(), edit) s.verifyEditStatus(models.VoteStatusEnumImmediateAccepted.String(), edit) s.verifyEditTargetType(models.TargetTypeEnumStudio.String(), edit) s.verifyEditApplication(true, edit) // ensure basic attributes are set correctly assert.Equal(s.t, *input.Name, updatedStudio.Name) assert.True(s.t, updatedStudio.ParentStudioID.Valid && (*input.ParentID == updatedStudio.ParentStudioID.UUID)) urls, _ := s.resolver.Studio().Urls(s.ctx, updatedStudio) assert.Equal(s.t, input.Urls, urls) } func (s *studioEditTestRunner) testApplyModifyUnsetStudioEdit() { existingName := "studioName4" site, err := s.createTestSite(nil) assert.NoError(s.t, err) newParent, err := s.createTestStudio(nil) assert.NoError(s.t, err) newParentID := newParent.UUID() studioCreateInput := models.StudioCreateInput{ Name: existingName, Urls: []models.URL{{ URL: "http://example.org/old", SiteID: site.ID, }}, ParentID: &newParentID, } createdStudio, err := s.createTestStudio(&studioCreateInput) assert.NoError(s.t, err) var resp struct { StudioEdit struct { ID string } } newName := "cleared-name" id := createdStudio.UUID() s.client.MustPost(fmt.Sprintf(` mutation { studioEdit(input: { edit: {id: "%v", operation: MODIFY} details: { parent_id: null, urls: [], name: "%s"} }) { id } } `, id, newName), &resp) _, err = s.applyEdit(uuid.FromStringOrNil(resp.StudioEdit.ID)) assert.NoError(s.t, err) var studio struct { FindStudio struct { Name string Parent struct { Id uuid.NullUUID } URLs []models.URL } } s.client.MustPost(fmt.Sprintf(` query { findStudio(id: "%v") { name parent { id } urls { url } } } `, id), &studio) assert.Equal(s.t, newName, studio.FindStudio.Name) assert.True(s.t, studio.FindStudio.Parent.Id.UUID.IsNil()) assert.True(s.t, len(studio.FindStudio.URLs) == 0) } func (s *studioEditTestRunner) testApplyDestroyStudioEdit() { createdStudio, err := s.createTestStudio(nil) assert.NoError(s.t, err) studioID := createdStudio.UUID() sceneInput := models.SceneCreateInput{ StudioID: &studioID, Date: "2020-03-02", } scene, err := s.createTestScene(&sceneInput) assert.NoError(s.t, err) studioEditDetailsInput := models.StudioEditDetailsInput{} editInput := models.EditInput{ Operation: models.OperationEnumDestroy, ID: &studioID, } destroyEdit, err := s.createTestStudioEdit(models.OperationEnumDestroy, &studioEditDetailsInput, &editInput) assert.NoError(s.t, err) appliedEdit, err := s.applyEdit(destroyEdit.ID) assert.NoError(s.t, err) destroyedStudio, err := s.resolver.Query().FindStudio(s.ctx, &studioID, nil) assert.NoError(s.t, err) scene, err = s.client.findScene(scene.UUID()) assert.NoError(s.t, err) s.verifyApplyDestroyStudioEdit(destroyedStudio, appliedEdit, scene) } func (s *studioEditTestRunner) verifyApplyDestroyStudioEdit(destroyedStudio *models.Studio, edit *models.Edit, scene *sceneOutput) { s.verifyEditOperation(models.OperationEnumDestroy.String(), edit) s.verifyEditStatus(models.VoteStatusEnumImmediateAccepted.String(), edit) s.verifyEditTargetType(models.TargetTypeEnumStudio.String(), edit) s.verifyEditApplication(true, edit) assert.Equal(s.t, destroyedStudio.Deleted, true) assert.Nil(s.t, scene.Studio) } func (s *studioEditTestRunner) testApplyMergeStudioEdit() { mergeSource1, err := s.createTestStudio(nil) assert.NoError(s.t, err) mergeSource2, err := s.createTestStudio(nil) assert.NoError(s.t, err) mergeTarget, err := s.createTestStudio(nil) assert.NoError(s.t, err) // Scene with studio from both source and target, should not cause db unique error mergeTargetID := mergeTarget.UUID() sceneInput := models.SceneCreateInput{ StudioID: &mergeTargetID, Date: "2020-03-02", } scene1, err := s.createTestScene(&sceneInput) assert.NoError(s.t, err) mergeSource1ID := mergeSource1.UUID() sceneInput = models.SceneCreateInput{ StudioID: &mergeSource1ID, Date: "2020-03-02", } scene2, err := s.createTestScene(&sceneInput) assert.NoError(s.t, err) newName := "newName4" studioEditDetailsInput := models.StudioEditDetailsInput{ Name: &newName, } id := mergeTarget.UUID() mergeSources := []uuid.UUID{mergeSource1.UUID(), mergeSource2.UUID()} editInput := models.EditInput{ Operation: models.OperationEnumMerge, ID: &id, MergeSourceIds: mergeSources, } mergeEdit, err := s.createTestStudioEdit(models.OperationEnumMerge, &studioEditDetailsInput, &editInput) assert.NoError(s.t, err) appliedMerge, err := s.applyEdit(mergeEdit.ID) assert.NoError(s.t, err) scene1, err = s.client.findScene(scene1.UUID()) assert.NoError(s.t, err) scene2, err = s.client.findScene(scene2.UUID()) assert.NoError(s.t, err) s.verifyAppliedMergeStudioEdit(studioEditDetailsInput, appliedMerge, scene1, scene2) } func (s *studioEditTestRunner) verifyAppliedMergeStudioEdit(input models.StudioEditDetailsInput, edit *models.Edit, scene1 *sceneOutput, scene2 *sceneOutput) { s.verifyEditOperation(models.OperationEnumMerge.String(), edit) s.verifyEditStatus(models.VoteStatusEnumImmediateAccepted.String(), edit) s.verifyEditTargetType(models.TargetTypeEnumStudio.String(), edit) s.verifyEditApplication(true, edit) studioDetails := s.getEditStudioDetails(edit) assert.Equal(s.t, *input.Name, *studioDetails.Name) merges, _ := s.resolver.Edit().MergeSources(s.ctx, edit) for i := range merges { studio := merges[i].(*models.Studio) assert.Equal(s.t, studio.Deleted, true) } editTarget := s.getEditStudioTarget(edit) assert.Equal(s.t, scene1.Studio.ID, editTarget.ID.String()) assert.Equal(s.t, scene2.Studio.ID, editTarget.ID.String()) } func (s *studioEditTestRunner) testStudioEditUpdate() { // Create a pending edit name := "Original Studio Name" studioEditDetailsInput := models.StudioEditDetailsInput{ Name: &name, } createdEdit, err := s.createTestStudioEdit(models.OperationEnumCreate, &studioEditDetailsInput, nil) assert.NoError(s.t, err) // Update the edit with new details newName := "Updated Studio Name" updatedDetails := models.StudioEditDetailsInput{ Name: &newName, } editID := createdEdit.ID updatedEdit, err := s.resolver.Mutation().StudioEditUpdate(s.ctx, createdEdit.ID, models.StudioEditInput{ Edit: &models.EditInput{ID: &editID}, Details: &updatedDetails, }) assert.NoError(s.t, err, "Error updating studio edit") // Verify the edit was updated assert.Equal(s.t, createdEdit.ID, updatedEdit.ID, "Edit ID should not change") assert.NotNil(s.t, updatedEdit, "Updated edit should not be nil") } func TestCreateStudioEdit(t *testing.T) { pt := createStudioEditTestRunner(t) pt.testCreateStudioEdit() } func TestModifyStudioEdit(t *testing.T) { pt := createStudioEditTestRunner(t) pt.testModifyStudioEdit() } func TestDestroyStudioEdit(t *testing.T) { pt := createStudioEditTestRunner(t) pt.testDestroyStudioEdit() } func TestMergeStudioEdit(t *testing.T) { pt := createStudioEditTestRunner(t) pt.testMergeStudioEdit() } func TestApplyCreateStudioEdit(t *testing.T) { pt := createStudioEditTestRunner(t) pt.testApplyCreateStudioEdit() } func TestApplyModifyStudioEdit(t *testing.T) { pt := createStudioEditTestRunner(t) pt.testApplyModifyStudioEdit() } func TestApplyModifyUnsetStudioEdit(t *testing.T) { pt := createStudioEditTestRunner(t) pt.testApplyModifyUnsetStudioEdit() } func TestApplyDestroyStudioEdit(t *testing.T) { pt := createStudioEditTestRunner(t) pt.testApplyDestroyStudioEdit() } func TestApplyMergeStudioEdit(t *testing.T) { pt := createStudioEditTestRunner(t) pt.testApplyMergeStudioEdit() } func TestStudioEditUpdate(t *testing.T) { pt := createStudioEditTestRunner(t) pt.testStudioEditUpdate() } ================================================ FILE: internal/api/studio_integration_test.go ================================================ //go:build integration package api_test import ( "strconv" "testing" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" "github.com/stretchr/testify/assert" ) type studioTestRunner struct { testRunner studioSuffix int } func createStudioTestRunner(t *testing.T) *studioTestRunner { return &studioTestRunner{ testRunner: *asModify(t), } } func (s *studioTestRunner) generateStudioName() string { s.studioSuffix += 1 return "studioTestRunner-" + strconv.Itoa(s.studioSuffix) } func (s *studioTestRunner) testCreateStudio() { input := models.StudioCreateInput{ Name: s.generateStudioName(), } studio, err := s.resolver.Mutation().StudioCreate(s.ctx, input) assert.NoError(s.t, err, "Error creating studio") s.verifyCreatedStudio(input, studio) } func (s *studioTestRunner) verifyCreatedStudio(input models.StudioCreateInput, studio *models.Studio) { // ensure basic attributes are set correctly assert.Equal(s.t, input.Name, studio.Name) assert.True(s.t, studio.ID != uuid.Nil, "Expected created studio id to be non-zero") } func (s *studioTestRunner) testFindStudioById() { createdStudio, err := s.createTestStudio(nil) assert.NoError(s.t, err) studioID := createdStudio.UUID() studio, err := s.resolver.Query().FindStudio(s.ctx, &studioID, nil) assert.NoError(s.t, err, "Error finding studio") // ensure returned studio is not nil assert.NotNil(s.t, studio, "Did not find studio by id") // ensure values were set assert.Equal(s.t, createdStudio.Name, studio.Name) } func (s *studioTestRunner) testFindStudioByName() { createdStudio, err := s.createTestStudio(nil) assert.NoError(s.t, err) studioName := createdStudio.Name studio, err := s.resolver.Query().FindStudio(s.ctx, nil, &studioName) assert.NoError(s.t, err, "Error finding studio") // ensure returned studio is not nil assert.NotNil(s.t, studio, "Did not find studio by name") // ensure values were set assert.Equal(s.t, createdStudio.Name, studio.Name) } func (s *studioTestRunner) testUpdateStudioName() { input := &models.StudioCreateInput{ Name: s.generateStudioName(), } createdStudio, err := s.createTestStudio(input) assert.NoError(s.t, err) studioID := createdStudio.UUID() updatedName := s.generateStudioName() updateInput := models.StudioUpdateInput{ ID: studioID, Name: &updatedName, } // need some mocking of the context to make the field ignore behaviour work ctx := s.updateContext([]string{ "name", }) updatedStudio, err := s.resolver.Mutation().StudioUpdate(ctx, updateInput) assert.NoError(s.t, err, "Error updating studio") input.Name = updatedName s.verifyCreatedStudio(*input, updatedStudio) } func (s *studioTestRunner) verifyUpdatedStudio(input models.StudioUpdateInput, studio *models.Studio) { // ensure basic attributes are set correctly assert.True(s.t, input.Name == nil || (*input.Name == studio.Name)) } func (s *studioTestRunner) testDestroyStudio() { createdStudio, err := s.createTestStudio(nil) assert.NoError(s.t, err) studioID := createdStudio.UUID() destroyed, err := s.resolver.Mutation().StudioDestroy(s.ctx, models.StudioDestroyInput{ ID: studioID, }) assert.NoError(s.t, err, "Error destroying studio") assert.True(s.t, destroyed, "Studio was not destroyed") // ensure cannot find studio foundStudio, err := s.resolver.Query().FindStudio(s.ctx, &studioID, nil) assert.NoError(s.t, err, "Error finding studio after destroying") assert.True(s.t, foundStudio == nil, nil, "Found studio after destruction") // TODO - ensure scene was not removed } func (s *studioTestRunner) testQueryStudios() { // Create test studios name1 := s.generateStudioName() studio1, err := s.createTestStudio(&models.StudioCreateInput{ Name: name1, }) assert.NoError(s.t, err) name2 := s.generateStudioName() studio2, err := s.createTestStudio(&models.StudioCreateInput{ Name: name2, }) assert.NoError(s.t, err) // Test basic query result, err := s.client.queryStudios(models.StudioQueryInput{ Page: 1, PerPage: 100, Direction: models.SortDirectionEnumAsc, Sort: models.StudioSortEnumName, }) assert.NoError(s.t, err, "Error querying studios") // Ensure we have at least the studios we created assert.True(s.t, result.Count >= 2, "Expected at least 2 studios in count") assert.True(s.t, len(result.Studios) >= 2, "Expected at least 2 studios in results") // Debug: check studio IDs s.t.Logf("Looking for studio1 ID: %s, studio2 ID: %s", studio1.ID, studio2.ID) s.t.Logf("Query returned %d studios", len(result.Studios)) // Verify our created studios are in the results found1 := false found2 := false for _, st := range result.Studios { if st.ID == studio1.ID { found1 = true assert.Equal(s.t, name1, st.Name) } if st.ID == studio2.ID { found2 = true assert.Equal(s.t, name2, st.Name) } } assert.True(s.t, found1, "Created studio 1 not found in query results") assert.True(s.t, found2, "Created studio 2 not found in query results") } func TestCreateStudio(t *testing.T) { pt := createStudioTestRunner(t) pt.testCreateStudio() } func TestFindStudioById(t *testing.T) { pt := createStudioTestRunner(t) pt.testFindStudioById() } func TestFindStudioByName(t *testing.T) { pt := createStudioTestRunner(t) pt.testFindStudioByName() } func TestUpdateStudioName(t *testing.T) { pt := createStudioTestRunner(t) pt.testUpdateStudioName() } func TestDestroyStudio(t *testing.T) { pt := createStudioTestRunner(t) pt.testDestroyStudio() } func TestQueryStudios(t *testing.T) { pt := createStudioTestRunner(t) pt.testQueryStudios() } func (s *studioTestRunner) testParentChildStudios() { // Create parent studio parentInput := models.StudioCreateInput{ Name: s.generateStudioName(), } parentStudio, err := s.resolver.Mutation().StudioCreate(s.ctx, parentInput) assert.NoError(s.t, err, "Error creating parent studio") parentID := parentStudio.ID // Create child studios child1Input := models.StudioCreateInput{ Name: s.generateStudioName(), ParentID: &parentID, } child1, err := s.resolver.Mutation().StudioCreate(s.ctx, child1Input) assert.NoError(s.t, err, "Error creating child studio 1") child2Input := models.StudioCreateInput{ Name: s.generateStudioName(), ParentID: &parentID, } child2, err := s.resolver.Mutation().StudioCreate(s.ctx, child2Input) assert.NoError(s.t, err, "Error creating child studio 2") child3Input := models.StudioCreateInput{ Name: s.generateStudioName(), ParentID: &parentID, } child3, err := s.resolver.Mutation().StudioCreate(s.ctx, child3Input) assert.NoError(s.t, err, "Error creating child studio 3") // Query parent studio using GraphQL client to get child_studios field queriedParent, err := s.client.findStudio(parentID) assert.NoError(s.t, err, "Error finding parent studio") assert.NotNil(s.t, queriedParent, "Parent studio not found") // Verify child_studios field contains the created children assert.Equal(s.t, 3, len(queriedParent.ChildStudios), "Expected 3 child studios") // Verify all child IDs are present childIDs := make(map[string]bool) for _, child := range queriedParent.ChildStudios { childIDs[child.ID] = true } assert.True(s.t, childIDs[child1.ID.String()], "Child1 not found in parent's child_studios") assert.True(s.t, childIDs[child2.ID.String()], "Child2 not found in parent's child_studios") assert.True(s.t, childIDs[child3.ID.String()], "Child3 not found in parent's child_studios") // Verify each child has correct parent for _, childID := range []uuid.UUID{child1.ID, child2.ID, child3.ID} { child, err := s.resolver.Query().FindStudio(s.ctx, &childID, nil) assert.NoError(s.t, err, "Error finding child studio") assert.NotNil(s.t, child, "Child studio not found") parent, err := s.resolver.Studio().Parent(s.ctx, child) assert.NoError(s.t, err, "Error getting parent from child") assert.NotNil(s.t, parent, "Parent not found from child") assert.Equal(s.t, parentID, parent.ID, "Child's parent ID doesn't match") } } func TestParentChildStudios(t *testing.T) { pt := createStudioTestRunner(t) pt.testParentChildStudios() } ================================================ FILE: internal/api/tag_category_integration_test.go ================================================ //go:build integration package api_test import ( "testing" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" "github.com/stretchr/testify/assert" ) type tagCategoryTestRunner struct { testRunner } func createTagCategoryTestRunner(t *testing.T) *tagCategoryTestRunner { return &tagCategoryTestRunner{ testRunner: *asAdmin(t), } } func (s *tagCategoryTestRunner) testCreateTagCategory() { description := "Description" input := models.TagCategoryCreateInput{ Name: s.generateCategoryName(), Description: &description, Group: models.TagGroupEnumPeople, } category, err := s.resolver.Mutation().TagCategoryCreate(s.ctx, input) assert.NoError(s.t, err, "Error creating tagCategory") s.verifyCreatedTagCategory(input, category) } func (s *tagCategoryTestRunner) verifyCreatedTagCategory(input models.TagCategoryCreateInput, category *models.TagCategory) { // ensure basic attributes are set correctly assert.Equal(s.t, input.Name, category.Name) r := s.resolver.TagCategory() assert.True(s.t, category.ID != uuid.Nil, "Expected created tagCategory id to be non-zero") assert.Equal(s.t, category.Description, input.Description) group, _ := r.Group(s.ctx, category) assert.Equal(s.t, group, models.TagGroupEnumPeople) } func (s *tagCategoryTestRunner) testFindTagCategoryById() { createdCategory, err := s.createTestTagCategory(nil) assert.NoError(s.t, err) category, err := s.resolver.Query().FindTagCategory(s.ctx, createdCategory.ID) assert.NoError(s.t, err, "Error finding tagCategory") // ensure returned tagCategory is not nil assert.NotNil(s.t, category, "Did not find tagCategory by id") // ensure values were set assert.Equal(s.t, createdCategory.Name, category.Name) } func (s *tagCategoryTestRunner) testUpdateTagCategory() { createdCategory, err := s.createTestTagCategory(nil) assert.NoError(s.t, err) catID := createdCategory.ID newDescription := "newDescription" updateInput := models.TagCategoryUpdateInput{ ID: catID, Description: &newDescription, } updatedCategory, err := s.resolver.Mutation().TagCategoryUpdate(s.ctx, updateInput) assert.NoError(s.t, err, "Error updating tagCategory") s.verifyUpdatedTagCategory(updateInput, updatedCategory) } func (s *tagCategoryTestRunner) verifyUpdatedTagCategory(input models.TagCategoryUpdateInput, category *models.TagCategory) { // ensure basic attributes are set correctly assert.True(s.t, input.Name == nil || (*input.Name == category.Name)) assert.Equal(s.t, category.Description, input.Description) } func (s *tagCategoryTestRunner) testDestroyTagCategory() { createdCategory, err := s.createTestTagCategory(nil) assert.NoError(s.t, err) catID := createdCategory.ID destroyed, err := s.resolver.Mutation().TagCategoryDestroy(s.ctx, models.TagCategoryDestroyInput{ ID: catID, }) assert.NoError(s.t, err, "Error destroying tagCategory") assert.True(s.t, destroyed, "TagCategory was not destroyed") // ensure cannot find tagCategory foundTagCategory, err := s.resolver.Query().FindTagCategory(s.ctx, catID) assert.NoError(s.t, err, "Error finding tagCategory after destroying") assert.Nil(s.t, foundTagCategory, "Found tagCategory after destruction") } func (s *tagCategoryTestRunner) testQueryTagCategories() { // Create test tag categories cat1, err := s.createTestTagCategory(nil) assert.NoError(s.t, err) cat2, err := s.createTestTagCategory(nil) assert.NoError(s.t, err) // Query all tag categories result, err := s.client.queryTagCategories() assert.NoError(s.t, err, "Error querying tag categories") // Ensure we have at least the categories we created assert.True(s.t, result.Count >= 2, "Expected at least 2 tag categories in count") assert.True(s.t, len(result.TagCategories) >= 2, "Expected at least 2 tag categories in results") // Verify our created categories are in the results found1 := false found2 := false for _, tc := range result.TagCategories { if tc.ID == cat1.ID.String() { found1 = true assert.Equal(s.t, cat1.Name, tc.Name) } if tc.ID == cat2.ID.String() { found2 = true assert.Equal(s.t, cat2.Name, tc.Name) } } assert.True(s.t, found1, "Created tag category 1 not found in query results") assert.True(s.t, found2, "Created tag category 2 not found in query results") } func TestCreateTagCategory(t *testing.T) { pt := createTagCategoryTestRunner(t) pt.testCreateTagCategory() } func TestUpdateTagCategory(t *testing.T) { pt := createTagCategoryTestRunner(t) pt.testUpdateTagCategory() } func TestDestroyTagCategory(t *testing.T) { pt := createTagCategoryTestRunner(t) pt.testDestroyTagCategory() } func TestQueryTagCategories(t *testing.T) { pt := createTagCategoryTestRunner(t) pt.testQueryTagCategories() } ================================================ FILE: internal/api/tag_edit_integration_test.go ================================================ //go:build integration package api_test import ( "testing" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" "github.com/stretchr/testify/assert" ) type tagEditTestRunner struct { testRunner } func createTagEditTestRunner(t *testing.T) *tagEditTestRunner { return &tagEditTestRunner{ testRunner: *asAdmin(t), } } func (s *tagEditTestRunner) testCreateTagEdit() { category, err := s.createTestTagCategory(nil) assert.NoError(s.t, err) categoryID := category.ID name := "Name" description := "Description" tagEditDetailsInput := models.TagEditDetailsInput{ Name: &name, Description: &description, Aliases: []string{"Alias1"}, CategoryID: &categoryID, } edit, err := s.createTestTagEdit(models.OperationEnumCreate, &tagEditDetailsInput, nil) assert.NoError(s.t, err) s.verifyCreatedTagEdit(tagEditDetailsInput, edit) } func (s *tagEditTestRunner) verifyCreatedTagEdit(input models.TagEditDetailsInput, edit *models.Edit) { r := s.resolver.Edit() assert.True(s.t, edit.ID != uuid.Nil, "Expected created edit id to be non-zero") details, _ := r.Details(s.ctx, edit) tagDetails := details.(*models.TagEdit) s.verifyEditOperation(models.OperationEnumCreate.String(), edit) s.verifyEditStatus(models.VoteStatusEnumPending.String(), edit) s.verifyEditTargetType(models.TargetTypeEnumTag.String(), edit) s.verifyEditApplication(false, edit) // ensure basic attributes are set correctly assert.Equal(s.t, *input.Name, *tagDetails.Name) assert.Equal(s.t, *input.Description, *tagDetails.Description) assert.Equal(s.t, input.Aliases, tagDetails.AddedAliases) assert.Equal(s.t, *input.CategoryID, *tagDetails.CategoryID) } func (s *tagEditTestRunner) testFindEditById() { createdEdit, err := s.createTestTagEdit(models.OperationEnumCreate, nil, nil) assert.NoError(s.t, err) edit, err := s.resolver.Query().FindEdit(s.ctx, createdEdit.ID) assert.NoError(s.t, err, "Error finding edit") // ensure returned tag is not nil assert.NotNil(s.t, edit, "Did not find edit by id") } func (s *tagEditTestRunner) testModifyTagEdit() { existingCategory, err := s.createTestTagCategory(nil) assert.NoError(s.t, err) existingCategoryID := existingCategory.ID existingName := "tagName" existingAlias := "tagAlias" tagCreateInput := models.TagCreateInput{ Name: existingName, Aliases: []string{existingAlias}, CategoryID: &existingCategoryID, } createdTag, err := s.createTestTag(&tagCreateInput) assert.NoError(s.t, err) newCategory, err := s.createTestTagCategory(nil) assert.NoError(s.t, err) newCategoryID := newCategory.ID newDescription := "newDescription" newAlias := "newTagAlias" newName := "newName" tagEditDetailsInput := models.TagEditDetailsInput{ Name: &newName, Description: &newDescription, Aliases: []string{newAlias}, CategoryID: &newCategoryID, } id := createdTag.UUID() editInput := models.EditInput{ Operation: models.OperationEnumModify, ID: &id, } createdUpdateEdit, err := s.createTestTagEdit(models.OperationEnumModify, &tagEditDetailsInput, &editInput) assert.NoError(s.t, err) s.verifyUpdatedTagEdit(createdTag, tagEditDetailsInput, createdUpdateEdit) } func (s *tagEditTestRunner) verifyUpdatedTagEdit(originalTag *tagOutput, input models.TagEditDetailsInput, edit *models.Edit) { tagDetails := s.getEditTagDetails(edit) s.verifyEditOperation(models.OperationEnumModify.String(), edit) s.verifyEditStatus(models.VoteStatusEnumPending.String(), edit) s.verifyEditTargetType(models.TargetTypeEnumTag.String(), edit) s.verifyEditApplication(false, edit) // ensure basic attributes are set correctly assert.Equal(s.t, *input.Name, *tagDetails.Name) assert.Equal(s.t, *input.Description, *tagDetails.Description) tagAliases := originalTag.Aliases assert.Equal(s.t, tagAliases, tagDetails.RemovedAliases) assert.Equal(s.t, input.Aliases, tagDetails.AddedAliases) assert.Equal(s.t, *input.CategoryID, *tagDetails.CategoryID) } func (s *tagEditTestRunner) testDestroyTagEdit() { createdTag, err := s.createTestTag(nil) assert.NoError(s.t, err) tagID := createdTag.UUID() tagEditDetailsInput := models.TagEditDetailsInput{} editInput := models.EditInput{ Operation: models.OperationEnumDestroy, ID: &tagID, } destroyEdit, err := s.createTestTagEdit(models.OperationEnumDestroy, &tagEditDetailsInput, &editInput) assert.NoError(s.t, err) s.verifyDestroyTagEdit(tagID, destroyEdit) } func (s *tagEditTestRunner) verifyDestroyTagEdit(tagID uuid.UUID, edit *models.Edit) { s.verifyEditOperation(models.OperationEnumDestroy.String(), edit) s.verifyEditStatus(models.VoteStatusEnumPending.String(), edit) s.verifyEditTargetType(models.TargetTypeEnumTag.String(), edit) s.verifyEditApplication(false, edit) editTarget := s.getEditTagTarget(edit) assert.Equal(s.t, tagID, editTarget.ID) } func (s *tagEditTestRunner) testMergeTagEdit() { existingName := "tagName2" existingAlias := "tagAlias2" tagCreateInput := models.TagCreateInput{ Name: existingName, Aliases: []string{existingAlias}, } createdPrimaryTag, err := s.createTestTag(&tagCreateInput) assert.NoError(s.t, err) createdMergeTag, err := s.createTestTag(nil) assert.NoError(s.t, err) newDescription := "newDescription2" newAlias := "newTagAlias2" newName := "newName2" tagEditDetailsInput := models.TagEditDetailsInput{ Name: &newName, Description: &newDescription, Aliases: []string{newAlias}, } id := createdPrimaryTag.UUID() mergeSources := []uuid.UUID{createdMergeTag.UUID()} editInput := models.EditInput{ Operation: models.OperationEnumMerge, ID: &id, MergeSourceIds: mergeSources, } createdMergeEdit, err := s.createTestTagEdit(models.OperationEnumMerge, &tagEditDetailsInput, &editInput) assert.NoError(s.t, err) s.verifyMergeTagEdit(createdPrimaryTag, tagEditDetailsInput, createdMergeEdit, mergeSources) } func (s *tagEditTestRunner) verifyMergeTagEdit(originalTag *tagOutput, input models.TagEditDetailsInput, edit *models.Edit, inputMergeSources []uuid.UUID) { tagDetails := s.getEditTagDetails(edit) s.verifyEditOperation(models.OperationEnumMerge.String(), edit) s.verifyEditStatus(models.VoteStatusEnumPending.String(), edit) s.verifyEditTargetType(models.TargetTypeEnumTag.String(), edit) s.verifyEditApplication(false, edit) // ensure basic attributes are set correctly assert.Equal(s.t, *input.Name, *tagDetails.Name) assert.Equal(s.t, *input.Description, *tagDetails.Description) tagAliases := originalTag.Aliases assert.Equal(s.t, tagAliases, tagDetails.RemovedAliases) assert.Equal(s.t, input.Aliases, tagDetails.AddedAliases) var mergeSources []uuid.UUID merges, _ := s.resolver.Edit().MergeSources(s.ctx, edit) for i := range merges { merge := merges[i].(*models.Tag) mergeSources = append(mergeSources, merge.ID) } assert.Equal(s.t, inputMergeSources, mergeSources) } func (s *tagEditTestRunner) testApplyCreateTagEdit() { name := "Name" description := "Description" category, err := s.createTestTagCategory(nil) assert.NoError(s.t, err) categoryID := category.ID tagEditDetailsInput := models.TagEditDetailsInput{ Name: &name, Description: &description, Aliases: []string{"Alias1"}, CategoryID: &categoryID, } edit, err := s.createTestTagEdit(models.OperationEnumCreate, &tagEditDetailsInput, nil) assert.NoError(s.t, err) appliedEdit, err := s.applyEdit(edit.ID) assert.NoError(s.t, err) s.verifyAppliedTagCreateEdit(tagEditDetailsInput, appliedEdit) } func (s *tagEditTestRunner) verifyAppliedTagCreateEdit(input models.TagEditDetailsInput, edit *models.Edit) { assert.True(s.t, edit.ID != uuid.Nil, "Expected created edit id to be non-zero") s.verifyEditOperation(models.OperationEnumCreate.String(), edit) s.verifyEditStatus(models.VoteStatusEnumImmediateAccepted.String(), edit) s.verifyEditTargetType(models.TargetTypeEnumTag.String(), edit) s.verifyEditApplication(true, edit) tag := s.getEditTagTarget(edit) // ensure basic attributes are set correctly assert.Equal(s.t, *input.Name, tag.Name) assert.Equal(s.t, *input.Description, *tag.Description) aliases, err := s.resolver.Tag().Aliases(s.ctx, tag) assert.NoError(s.t, err) assert.Equal(s.t, input.Aliases, aliases) assert.Equal(s.t, *input.CategoryID, tag.CategoryID.UUID) } func (s *tagEditTestRunner) testApplyModifyTagEdit() { existingName := "tagName3" existingAlias := "tagAlias3" tagCreateInput := models.TagCreateInput{ Name: existingName, Aliases: []string{existingAlias}, } createdTag, err := s.createTestTag(&tagCreateInput) assert.NoError(s.t, err) newDescription := "newDescription3" newAlias := "newTagAlias3" newName := "newName3" newCategory, err := s.createTestTagCategory(nil) assert.NoError(s.t, err) newCategoryID := newCategory.ID tagEditDetailsInput := models.TagEditDetailsInput{ Name: &newName, Description: &newDescription, Aliases: []string{newAlias}, CategoryID: &newCategoryID, } id := createdTag.UUID() editInput := models.EditInput{ Operation: models.OperationEnumModify, ID: &id, } createdUpdateEdit, err := s.createTestTagEdit(models.OperationEnumModify, &tagEditDetailsInput, &editInput) assert.NoError(s.t, err) appliedEdit, err := s.applyEdit(createdUpdateEdit.ID) assert.NoError(s.t, err) modifiedTag, err := s.resolver.Query().FindTag(s.ctx, &id, nil) assert.NoError(s.t, err) s.verifyApplyModifyTagEdit(tagEditDetailsInput, modifiedTag, appliedEdit) } func (s *tagEditTestRunner) verifyApplyModifyTagEdit(input models.TagEditDetailsInput, updatedTag *models.Tag, edit *models.Edit) { s.verifyEditOperation(models.OperationEnumModify.String(), edit) s.verifyEditStatus(models.VoteStatusEnumImmediateAccepted.String(), edit) s.verifyEditTargetType(models.TargetTypeEnumTag.String(), edit) s.verifyEditApplication(true, edit) // ensure basic attributes are set correctly assert.Equal(s.t, *input.Name, updatedTag.Name) assert.Equal(s.t, *input.Description, *updatedTag.Description) tagAliases, _ := s.resolver.Tag().Aliases(s.ctx, updatedTag) assert.Equal(s.t, input.Aliases, tagAliases) assert.True(s.t, updatedTag.CategoryID.Valid && (*input.CategoryID == updatedTag.CategoryID.UUID)) } func (s *tagEditTestRunner) testApplyDestroyTagEdit() { createdTag, err := s.createTestTag(nil) assert.NoError(s.t, err) tagID := createdTag.UUID() sceneInput := models.SceneCreateInput{ TagIds: []uuid.UUID{tagID}, Date: "2020-03-02", } scene, err := s.createTestScene(&sceneInput) assert.NoError(s.t, err) tagEditDetailsInput := models.TagEditDetailsInput{} editInput := models.EditInput{ Operation: models.OperationEnumDestroy, ID: &tagID, } destroyEdit, err := s.createTestTagEdit(models.OperationEnumDestroy, &tagEditDetailsInput, &editInput) assert.NoError(s.t, err) appliedEdit, err := s.applyEdit(destroyEdit.ID) assert.NoError(s.t, err) destroyedTag, err := s.resolver.Query().FindTag(s.ctx, &tagID, nil) assert.NoError(s.t, err) scene, err = s.client.findScene(scene.UUID()) assert.NoError(s.t, err, "Error finding scene") s.verifyApplyDestroyTagEdit(destroyedTag, appliedEdit, scene) } func (s *tagEditTestRunner) verifyApplyDestroyTagEdit(destroyedTag *models.Tag, edit *models.Edit, scene *sceneOutput) { s.verifyEditOperation(models.OperationEnumDestroy.String(), edit) s.verifyEditStatus(models.VoteStatusEnumImmediateAccepted.String(), edit) s.verifyEditTargetType(models.TargetTypeEnumTag.String(), edit) s.verifyEditApplication(true, edit) assert.Equal(s.t, destroyedTag.Deleted, true) sceneTags := scene.Tags assert.True(s.t, len(sceneTags) == 0) } func (s *tagEditTestRunner) testApplyMergeTagEdit() { mergeSource1, err := s.createTestTag(nil) assert.NoError(s.t, err) mergeSource2, err := s.createTestTag(nil) assert.NoError(s.t, err) mergeTarget, err := s.createTestTag(nil) assert.NoError(s.t, err) // Scene with tag from both source and target, should not cause db unique error sceneInput := models.SceneCreateInput{ TagIds: []uuid.UUID{mergeSource2.UUID(), mergeTarget.UUID()}, Date: "2020-03-02", } scene1, err := s.createTestScene(&sceneInput) assert.NoError(s.t, err) sceneInput = models.SceneCreateInput{ TagIds: []uuid.UUID{mergeSource1.UUID(), mergeSource2.UUID()}, Date: "2020-03-02", } scene2, err := s.createTestScene(&sceneInput) assert.NoError(s.t, err) newDescription := "newDescription4" newAlias := "newTagAlias4" newName := "newName4" tagEditDetailsInput := models.TagEditDetailsInput{ Name: &newName, Description: &newDescription, Aliases: []string{newAlias}, } id := mergeTarget.UUID() mergeSources := []uuid.UUID{mergeSource1.UUID(), mergeSource2.UUID()} editInput := models.EditInput{ Operation: models.OperationEnumMerge, ID: &id, MergeSourceIds: mergeSources, } mergeEdit, err := s.createTestTagEdit(models.OperationEnumMerge, &tagEditDetailsInput, &editInput) assert.NoError(s.t, err) appliedMerge, err := s.applyEdit(mergeEdit.ID) assert.NoError(s.t, err) scene1, err = s.client.findScene(scene1.UUID()) assert.NoError(s.t, err, "Error finding scene") scene2, err = s.client.findScene(scene2.UUID()) assert.NoError(s.t, err, "Error finding scene") s.verifyAppliedMergeTagEdit(tagEditDetailsInput, appliedMerge, scene1, scene2) } func (s *tagEditTestRunner) verifyAppliedMergeTagEdit(input models.TagEditDetailsInput, edit *models.Edit, scene1, scene2 *sceneOutput) { s.verifyEditOperation(models.OperationEnumMerge.String(), edit) s.verifyEditStatus(models.VoteStatusEnumImmediateAccepted.String(), edit) s.verifyEditTargetType(models.TargetTypeEnumTag.String(), edit) s.verifyEditApplication(true, edit) tagDetails := s.getEditTagDetails(edit) assert.Equal(s.t, *input.Name, *tagDetails.Name) assert.Equal(s.t, *input.Description, *tagDetails.Description) assert.Equal(s.t, input.Aliases, tagDetails.AddedAliases) merges, _ := s.resolver.Edit().MergeSources(s.ctx, edit) for i := range merges { tag := merges[i].(*models.Tag) assert.Equal(s.t, tag.Deleted, true) } editTarget := s.getEditTagTarget(edit) scene1Tags := scene1.Tags assert.Equal(s.t, len(scene1Tags), 1) assert.Equal(s.t, scene1Tags[0].ID, editTarget.ID.String()) scene2Tags := scene2.Tags assert.Equal(s.t, len(scene2Tags), 1) assert.Equal(s.t, scene2Tags[0].ID, editTarget.ID.String()) } func (s *tagEditTestRunner) testTagEditUpdate() { // Create a pending edit name := "Original Tag Name" tagEditDetailsInput := models.TagEditDetailsInput{ Name: &name, } createdEdit, err := s.createTestTagEdit(models.OperationEnumCreate, &tagEditDetailsInput, nil) assert.NoError(s.t, err) // Update the edit with new details newName := "Updated Tag Name" updatedDetails := models.TagEditDetailsInput{ Name: &newName, } editID := createdEdit.ID updatedEdit, err := s.resolver.Mutation().TagEditUpdate(s.ctx, createdEdit.ID, models.TagEditInput{ Edit: &models.EditInput{ID: &editID}, Details: &updatedDetails, }) assert.NoError(s.t, err, "Error updating tag edit") // Verify the edit was updated assert.Equal(s.t, createdEdit.ID, updatedEdit.ID, "Edit ID should not change") assert.NotNil(s.t, updatedEdit, "Updated edit should not be nil") } func TestCreateTagEdit(t *testing.T) { pt := createTagEditTestRunner(t) pt.testCreateTagEdit() } func TestModifyTagEdit(t *testing.T) { pt := createTagEditTestRunner(t) pt.testModifyTagEdit() } func TestDestroyTagEdit(t *testing.T) { pt := createTagEditTestRunner(t) pt.testDestroyTagEdit() } func TestMergeTagEdit(t *testing.T) { pt := createTagEditTestRunner(t) pt.testMergeTagEdit() } func TestApplyCreateTagEdit(t *testing.T) { pt := createTagEditTestRunner(t) pt.testApplyCreateTagEdit() } func TestApplyModifyTagEdit(t *testing.T) { pt := createTagEditTestRunner(t) pt.testApplyModifyTagEdit() } func TestApplyDestroyTagEdit(t *testing.T) { pt := createTagEditTestRunner(t) pt.testApplyDestroyTagEdit() } func TestApplyMergeTagEdit(t *testing.T) { pt := createTagEditTestRunner(t) pt.testApplyMergeTagEdit() } func TestTagEditUpdate(t *testing.T) { pt := createTagEditTestRunner(t) pt.testTagEditUpdate() } ================================================ FILE: internal/api/tag_integration_test.go ================================================ //go:build integration package api_test import ( "testing" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" "github.com/stretchr/testify/assert" ) type tagTestRunner struct { testRunner } func createTagTestRunner(t *testing.T) *tagTestRunner { return &tagTestRunner{ testRunner: *asModify(t), } } func (s *tagTestRunner) testCreateTag() { description := "Description" input := models.TagCreateInput{ Name: s.generateTagName(), Description: &description, } tag, err := s.resolver.Mutation().TagCreate(s.ctx, input) assert.NoError(s.t, err, "Error creating tag") s.verifyCreatedTag(input, tag) } func (s *tagTestRunner) verifyCreatedTag(input models.TagCreateInput, tag *models.Tag) { // ensure basic attributes are set correctly assert.Equal(s.t, input.Name, tag.Name) assert.True(s.t, tag.ID != uuid.Nil, "Expected created tag id to be non-zero") assert.Equal(s.t, tag.Description, input.Description) } func (s *tagTestRunner) testFindTagById() { createdTag, err := s.createTestTag(nil) assert.NoError(s.t, err) tagID := createdTag.UUID() tag, err := s.resolver.Query().FindTag(s.ctx, &tagID, nil) assert.NoError(s.t, err, "Error finding tag") // ensure returned tag is not nil assert.NotNil(s.t, tag, "Did not find tag by id") // ensure values were set assert.Equal(s.t, createdTag.Name, tag.Name) } func (s *tagTestRunner) testFindTagByName() { createdTag, err := s.createTestTag(nil) assert.NoError(s.t, err) tagName := createdTag.Name tag, err := s.resolver.Query().FindTag(s.ctx, nil, &tagName) assert.NoError(s.t, err, "Error finding tag") // ensure returned tag is not nil assert.NotNil(s.t, tag, "Did not find tag by name") // ensure values were set assert.Equal(s.t, createdTag.Name, tag.Name) } func (s *tagTestRunner) testUpdateTag() { createdTag, err := s.createTestTag(nil) assert.NoError(s.t, err) tagID := createdTag.UUID() newDescription := "newDescription" updateInput := models.TagUpdateInput{ ID: tagID, Description: &newDescription, } updatedTag, err := s.resolver.Mutation().TagUpdate(s.ctx, updateInput) assert.NoError(s.t, err, "Error updating tag") updateInput.Name = &createdTag.Name s.verifyUpdatedTag(updateInput, updatedTag) } func (s *tagTestRunner) verifyUpdatedTag(input models.TagUpdateInput, tag *models.Tag) { // ensure basic attributes are set correctly assert.True(s.t, input.Name == nil || (*input.Name == tag.Name)) assert.Equal(s.t, tag.Description, input.Description) } func (s *tagTestRunner) testDestroyTag() { createdTag, err := s.createTestTag(nil) assert.NoError(s.t, err) tagID := createdTag.UUID() destroyed, err := s.resolver.Mutation().TagDestroy(s.ctx, models.TagDestroyInput{ ID: tagID, }) assert.NoError(s.t, err, "Error destroying tag") assert.True(s.t, destroyed, "Tag was not destroyed") // ensure cannot find tag foundTag, err := s.resolver.Query().FindTag(s.ctx, &tagID, nil) assert.NoError(s.t, err, "Error finding tag after destroying") assert.Nil(s.t, foundTag, "Found tag after destruction") // TODO - ensure scene was not removed } func (s *tagTestRunner) testQueryTags() { // Create test tags name1 := s.generateTagName() tag1, err := s.createTestTag(&models.TagCreateInput{ Name: name1, }) assert.NoError(s.t, err) name2 := s.generateTagName() tag2, err := s.createTestTag(&models.TagCreateInput{ Name: name2, }) assert.NoError(s.t, err) // Test basic query result, err := s.client.queryTags(models.TagQueryInput{ Page: 1, PerPage: 100, Direction: models.SortDirectionEnumAsc, Sort: models.TagSortEnumName, }) assert.NoError(s.t, err, "Error querying tags") // Ensure we have at least the tags we created assert.True(s.t, result.Count >= 2, "Expected at least 2 tags in count") assert.True(s.t, len(result.Tags) >= 2, "Expected at least 2 tags in results") // Debug: check tag IDs s.t.Logf("Looking for tag1 ID: %s, tag2 ID: %s", tag1.ID, tag2.ID) s.t.Logf("Query returned %d tags", len(result.Tags)) // Verify our created tags are in the results found1 := false found2 := false for _, tag := range result.Tags { if tag.ID == tag1.ID { found1 = true assert.Equal(s.t, name1, tag.Name) } if tag.ID == tag2.ID { found2 = true assert.Equal(s.t, name2, tag.Name) } } assert.True(s.t, found1, "Created tag 1 not found in query results") assert.True(s.t, found2, "Created tag 2 not found in query results") } func (s *tagTestRunner) testFindTagOrAlias() { // Create a tag with aliases tagName := s.generateTagName() alias1 := "alias1-" + tagName alias2 := "alias2-" + tagName tag, err := s.createTestTag(&models.TagCreateInput{ Name: tagName, Aliases: []string{alias1, alias2}, }) assert.NoError(s.t, err) // Test finding by name foundByName, err := s.client.findTagOrAlias(tagName) assert.NoError(s.t, err, "Error finding tag by name") assert.NotNil(s.t, foundByName, "Did not find tag by name") assert.Equal(s.t, tag.ID, foundByName.ID) // Test finding by alias foundByAlias, err := s.client.findTagOrAlias(alias1) assert.NoError(s.t, err, "Error finding tag by alias") assert.NotNil(s.t, foundByAlias, "Did not find tag by alias") assert.Equal(s.t, tag.ID, foundByAlias.ID) // Test not finding non-existent tag/alias notFound, err := s.client.findTagOrAlias("non-existent-tag-12345") assert.NoError(s.t, err, "Error finding non-existent tag") assert.Nil(s.t, notFound, "Found tag that shouldn't exist") } func TestCreateTag(t *testing.T) { pt := createTagTestRunner(t) pt.testCreateTag() } func TestFindTagById(t *testing.T) { pt := createTagTestRunner(t) pt.testFindTagById() } func TestFindTagByName(t *testing.T) { pt := createTagTestRunner(t) pt.testFindTagByName() } func TestUpdateTag(t *testing.T) { pt := createTagTestRunner(t) pt.testUpdateTag() } func TestDestroyTag(t *testing.T) { pt := createTagTestRunner(t) pt.testDestroyTag() } func TestQueryTags(t *testing.T) { pt := createTagTestRunner(t) pt.testQueryTags() } func TestFindTagOrAlias(t *testing.T) { pt := createTagTestRunner(t) pt.testFindTagOrAlias() } ================================================ FILE: internal/api/user_integration_test.go ================================================ //go:build integration package api_test import ( "context" "testing" "time" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/auth" "github.com/stashapp/stash-box/internal/models" "github.com/stretchr/testify/assert" ) type userTestRunner struct { testRunner } func createUserTestRunner(t *testing.T) *userTestRunner { return &userTestRunner{ testRunner: *asAdmin(t), } } func (s *userTestRunner) testCreateUser() { name := s.generateUserName() input := models.UserCreateInput{ Name: name, Password: "password" + name, Email: name + "@example.com", Roles: []models.RoleEnum{ models.RoleEnumAdmin, }, } user, err := s.resolver.Mutation().UserCreate(s.ctx, input) assert.NoError(s.t, err, "Error creating user") s.verifyCreatedUser(input, user) } func (s *userTestRunner) verifyCreatedUser(input models.UserCreateInput, user *models.User) { // ensure basic attributes are set correctly assert.Equal(s.t, input.Name, user.Name) assert.Equal(s.t, input.Email, user.Email) // ensure apikey is set assert.True(s.t, user.APIKey != "", "API key was not generated") assert.True(s.t, user.PasswordHash != "", "Password was not set") assert.True(s.t, user.ID != uuid.Nil, "Expected created user id to be non-zero") // TODO - ensure roles are set } func (s *userTestRunner) testFindUserById() { createdUser, err := s.createTestUser(nil, nil) assert.NoError(s.t, err) user, err := s.resolver.Query().FindUser(s.ctx, &createdUser.ID, nil) assert.NoError(s.t, err, "Error finding user") // ensure returned user is not nil assert.NotNil(s.t, user, "Did not find user by id") // ensure values were set assert.Equal(s.t, createdUser.Name, user.Name) } func (s *userTestRunner) testFindUserByName() { createdUser, err := s.createTestUser(nil, nil) assert.NoError(s.t, err) userName := createdUser.Name user, err := s.resolver.Query().FindUser(s.ctx, nil, &userName) assert.NoError(s.t, err, "Error finding user") // ensure returned user is not nil assert.NotNil(s.t, user, "Did not find user by name") // ensure values were set assert.Equal(s.t, createdUser.Name, user.Name) } func (s *userTestRunner) testQueryUserByName() { createdUser, err := s.createTestUser(nil, nil) assert.NoError(s.t, err) userName := createdUser.Name input := models.UserQueryInput{ Name: &userName, Page: 1, PerPage: 1, } result, err := s.resolver.Query().QueryUsers(s.ctx, input) assert.NoError(s.t, err, "Error querying user") // ensure one result was returned assert.Equal(s.t, result.Count, 1, "Expected 1 user") // ensure values were set assert.Equal(s.t, createdUser.Name, result.Users[0].Name) } func (s *userTestRunner) testUpdateUserName() { name := s.generateUserName() input := &models.UserCreateInput{ Name: name, Email: name + "@example.com", Password: "password" + name, } createdUser, err := s.createTestUser(input, nil) assert.NoError(s.t, err) userID := createdUser.ID updatedName := s.generateUserName() updateInput := models.UserUpdateInput{ ID: userID, Name: &updatedName, } // need some mocking of the context to make the field ignore behaviour work ctx := s.updateContext([]string{ "name", }) updatedUser, err := s.resolver.Mutation().UserUpdate(ctx, updateInput) assert.NoError(s.t, err, "Error updating user") input.Name = updatedName s.verifyCreatedUser(*input, updatedUser) } func (s *userTestRunner) testUpdatePassword() { name := s.generateUserName() input := &models.UserCreateInput{ Name: name, Email: name + "@example.com", Password: "password" + name, } createdUser, err := s.createTestUser(input, nil) assert.NoError(s.t, err) userID := createdUser.ID oldPassword := createdUser.PasswordHash updatedPassword := s.generateUserName() + "newpassword" updateInput := models.UserUpdateInput{ ID: userID, Password: &updatedPassword, } // need some mocking of the context to make the field ignore behaviour work ctx := s.updateContext([]string{ "password", }) updatedUser, err := s.resolver.Mutation().UserUpdate(ctx, updateInput) assert.NoError(s.t, err, "Error updating user") // ensure password is set assert.True(s.t, updatedUser.PasswordHash != "", "Password was not set") assert.True(s.t, updatedUser.PasswordHash != oldPassword, "Password was not changed") } func (s *userTestRunner) verifyUpdatedUser(input models.UserUpdateInput, user *models.User) { // ensure basic attributes are set correctly assert.True(s.t, input.Name == nil || *input.Name == user.Name) } func (s *userTestRunner) testDestroyUser() { createdUser, err := s.createTestUser(nil, nil) assert.NoError(s.t, err) userID := createdUser.ID destroyed, err := s.resolver.Mutation().UserDestroy(s.ctx, models.UserDestroyInput{ ID: userID, }) assert.NoError(s.t, err, "Error destroying user") assert.True(s.t, destroyed, "User was not destroyed") // ensure cannot find user foundUser, err := s.resolver.Query().FindUser(s.ctx, &userID, nil) assert.NoError(s.t, err, "Error finding user after destroying") assert.Nil(s.t, foundUser, "Found user after destruction") } func (s *userTestRunner) testUserQuery() { userName := userDB.admin.Name input := models.UserQueryInput{ Name: &userName, Page: 1, PerPage: 1, } users, err := s.resolver.Query().QueryUsers(s.ctx, input) assert.NoError(s.t, err) assert.Equal(s.t, len(users.Users), 1, "QueryUsers: admin user not found") } func (s *userTestRunner) testChangePassword() { name := s.generateUserName() oldPassword := "password" + name input := &models.UserCreateInput{ Name: name, Email: name + "@example.com", Password: oldPassword, } createdUser, err := s.createTestUser(input, nil) assert.NoError(s.t, err) // change password as the test user ctx := context.TODO() ctx = context.WithValue(ctx, auth.ContextUser, createdUser) updatedPassword := name + "newpassword" existingPassword := "incorrect password" updateInput := models.UserChangePasswordInput{ ExistingPassword: &existingPassword, NewPassword: updatedPassword, } _, err = s.resolver.Mutation().ChangePassword(ctx, updateInput) assert.Error(s.t, err, "current password incorrect", "Expected error for incorrect current password") updateInput.ExistingPassword = &oldPassword updateInput.NewPassword = "aaa" _, err = s.resolver.Mutation().ChangePassword(ctx, updateInput) assert.Error(s.t, err, "password length < 8", "Expected error for invalid new password") updateInput.NewPassword = updatedPassword _, err = s.resolver.Mutation().ChangePassword(ctx, updateInput) assert.NoError(s.t, err, "Error changing password") } func (s *userTestRunner) testRegenerateAPIKey() { name := s.generateUserName() input := &models.UserCreateInput{ Name: name, Email: name + "@example.com", Password: "password" + name, } createdUser, err := s.createTestUser(input, nil) assert.NoError(s.t, err) oldKey := createdUser.APIKey // regenerate as the test user ctx := context.TODO() ctx = context.WithValue(ctx, auth.ContextUser, createdUser) adminID := userDB.admin.ID _, err = s.resolver.Mutation().RegenerateAPIKey(ctx, &adminID) assert.Error(s.t, err, "not authorized", "Expected error for changing other user API key") // wait one second before regenerating to ensure a new key is created time.Sleep(1 * time.Second) newKey, err := s.resolver.Mutation().RegenerateAPIKey(ctx, nil) assert.NoError(s.t, err, "Error regenerating API key") assert.True(s.t, newKey != "", "Regenerated API key is empty") assert.True(s.t, newKey != oldKey, "Regenerated API key is same as old key") userID := createdUser.ID user, err := s.resolver.Query().FindUser(s.ctx, &userID, nil) assert.NoError(s.t, err, "Error finding user") assert.Equal(s.t, user.APIKey, newKey, "Returned API key s is different to stored key") } func (s *userTestRunner) testUserEditQuery() { createdUser, err := s.createTestUser(nil, nil) assert.NoError(s.t, err) userID := createdUser.ID filter := models.EditQueryInput{ UserID: &userID, } _, err = s.resolver.Query().QueryEdits(s.ctx, filter) assert.NoError(s.t, err, "Error finding user edits") // TODO: Test edits are returned } func TestCreateUser(t *testing.T) { pt := createUserTestRunner(t) pt.testCreateUser() } func TestFindUserById(t *testing.T) { pt := createUserTestRunner(t) pt.testFindUserById() } func TestFindUserByName(t *testing.T) { pt := createUserTestRunner(t) pt.testFindUserByName() } func TestQueryUserByName(t *testing.T) { pt := createUserTestRunner(t) pt.testQueryUserByName() } func TestUpdateUserName(t *testing.T) { pt := createUserTestRunner(t) pt.testUpdateUserName() } func TestUpdateUserPassword(t *testing.T) { pt := createUserTestRunner(t) pt.testUpdatePassword() } func TestDestroyUser(t *testing.T) { pt := createUserTestRunner(t) pt.testDestroyUser() } func TestUserQuery(t *testing.T) { pt := createUserTestRunner(t) pt.testUserQuery() } func TestChangePassword(t *testing.T) { pt := createUserTestRunner(t) pt.testChangePassword() } func TestRegenerateAPIKey(t *testing.T) { pt := createUserTestRunner(t) pt.testRegenerateAPIKey() } func TestUserEditQuery(t *testing.T) { pt := createUserTestRunner(t) pt.testUserEditQuery() } func (s *userTestRunner) testMeQuery() { // Test me query returns current authenticated user me, err := s.client.me() assert.NoError(s.t, err, "Error getting current user") assert.NotNil(s.t, me, "me query returned nil") assert.Equal(s.t, userDB.admin.ID.String(), me.ID, "me query returned wrong user") assert.Equal(s.t, userDB.admin.Name, me.Name, "me query returned wrong user name") } func (s *userTestRunner) testFavoritePerformer() { // Create a test performer performer, err := s.createTestPerformer(nil) assert.NoError(s.t, err) performerID := performer.UUID() // Favorite the performer result, err := s.client.favoritePerformer(performerID, true) assert.NoError(s.t, err, "Error favoriting performer") assert.True(s.t, result, "Expected favoritePerformer to return true") // Unfavorite the performer result, err = s.client.favoritePerformer(performerID, false) assert.NoError(s.t, err, "Error unfavoriting performer") assert.True(s.t, result, "Expected favoritePerformer to return true") } func (s *userTestRunner) testFavoriteStudio() { // Create a test studio studio, err := s.createTestStudio(nil) assert.NoError(s.t, err) studioID := studio.UUID() // Favorite the studio result, err := s.client.favoriteStudio(studioID, true) assert.NoError(s.t, err, "Error favoriting studio") assert.True(s.t, result, "Expected favoriteStudio to return true") // Unfavorite the studio result, err = s.client.favoriteStudio(studioID, false) assert.NoError(s.t, err, "Error unfavoriting studio") assert.True(s.t, result, "Expected favoriteStudio to return true") } func TestMeQuery(t *testing.T) { pt := createUserTestRunner(t) pt.testMeQuery() } func TestFavoritePerformer(t *testing.T) { pt := createUserTestRunner(t) pt.testFavoritePerformer() } func TestFavoriteStudio(t *testing.T) { pt := createUserTestRunner(t) pt.testFavoriteStudio() } func (s *userTestRunner) testQueryNotifications() { input := models.QueryNotificationsInput{ Page: 1, PerPage: 25, } result, err := s.client.queryNotifications(input) assert.NoError(s.t, err, "Error querying notifications") assert.NotNil(s.t, result, "Result should not be nil") assert.NotNil(s.t, result.Notifications, "Notifications should not be nil") } func (s *userTestRunner) testGetUnreadNotificationCount() { count, err := s.client.getUnreadNotificationCount() assert.NoError(s.t, err, "Error getting unread notification count") assert.True(s.t, count >= 0, "Count should be non-negative") } func (s *userTestRunner) testUpdateNotificationSubscriptions() { subscriptions := []models.NotificationEnum{ models.NotificationEnumFavoritePerformerScene, models.NotificationEnumFavoriteStudioScene, } result, err := s.client.updateNotificationSubscriptions(subscriptions) assert.NoError(s.t, err, "Error updating notification subscriptions") assert.True(s.t, result, "Update should return true") } func TestQueryNotifications(t *testing.T) { pt := createUserTestRunner(t) pt.testQueryNotifications() } func TestGetUnreadNotificationCount(t *testing.T) { pt := createUserTestRunner(t) pt.testGetUnreadNotificationCount() } func TestUpdateNotificationSubscriptions(t *testing.T) { pt := createUserTestRunner(t) pt.testUpdateNotificationSubscriptions() } func (s *userTestRunner) testNewUser() { // Grant invite tokens to the admin user adminID := userDB.admin.ID _, err := s.resolver.Mutation().GrantInvite(s.ctx, models.GrantInviteInput{ UserID: adminID, Amount: 10, }) assert.NoError(s.t, err, "Error granting invite tokens") // Generate an invite key if required inviteKey, err := s.resolver.Mutation().GenerateInviteCode(s.ctx) assert.NoError(s.t, err, "Error generating invite key") // Test 1: NewUser with valid email should succeed email := "newuser@example.com" input := models.NewUserInput{ Email: email, InviteKey: inviteKey, } activationKey, err := s.resolver.Mutation().NewUser(s.ctx, input) assert.NoError(s.t, err, "Error calling NewUser with valid email") assert.NotNil(s.t, activationKey, "Activation key should not be nil") // Test 2: NewUser with same email should fail (pending activation exists) inviteKey2, err := s.resolver.Mutation().GenerateInviteCode(s.ctx) assert.NoError(s.t, err, "Error generating second invite key") input.InviteKey = inviteKey2 _, err = s.resolver.Mutation().NewUser(s.ctx, input) assert.Error(s.t, err, "Expected error when email has pending activation") assert.Contains(s.t, err.Error(), "email already has a pending activation", "Error should mention pending activation") // Test 3: NewUser with existing user email should fail inviteKey3, err := s.resolver.Mutation().GenerateInviteCode(s.ctx) assert.NoError(s.t, err, "Error generating third invite key") existingEmail := userDB.admin.Email input2 := models.NewUserInput{ Email: existingEmail, InviteKey: inviteKey3, } _, err = s.resolver.Mutation().NewUser(s.ctx, input2) assert.Error(s.t, err, "Expected error when email already in use") assert.Contains(s.t, err.Error(), "email already in use", "Error should mention email already in use") } func TestNewUser(t *testing.T) { pt := createUserTestRunner(t) pt.testNewUser() } ================================================ FILE: internal/api/utils.go ================================================ package api import ( "fmt" "strings" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" ) func parseUUID(id string) uuid.UUID { trimmed := strings.TrimSpace(id) return uuid.FromStringOrNil(trimmed) } func resolveFuzzyDate(date *string) *models.FuzzyDate { if date == nil { return nil } switch { case len(*date) == 4: return &models.FuzzyDate{ Accuracy: models.DateAccuracyEnumYear, Date: fmt.Sprintf("%s-01-01", *date), } case len(*date) == 7: return &models.FuzzyDate{ Accuracy: models.DateAccuracyEnumMonth, Date: fmt.Sprintf("%s-01", *date), } case len(*date) == 10: return &models.FuzzyDate{ Accuracy: models.DateAccuracyEnumDay, Date: *date, } } return nil } ================================================ FILE: internal/auth/authorization.go ================================================ package auth import ( "context" "errors" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" ) type key int const ( ContextUser key = iota ContextRoles ) const APIKeyHeader = "ApiKey" var ErrUnauthorized = errors.New("not authorized") func GetCurrentUser(ctx context.Context) *models.User { userCtxVal := ctx.Value(ContextUser) if userCtxVal != nil { currentUser := userCtxVal.(*models.User) return currentUser } return nil } func IsRole(ctx context.Context, requiredRole models.RoleEnum) bool { var roles []models.RoleEnum roleCtxVal := ctx.Value(ContextRoles) if roleCtxVal != nil { roles = roleCtxVal.([]models.RoleEnum) } valid := false for _, role := range roles { if role.Implies(requiredRole) { valid = true break } } return valid } func ValidateRole(ctx context.Context, requiredRole models.RoleEnum) error { if !IsRole(ctx, requiredRole) { return ErrUnauthorized } return nil } func ValidateInvite(ctx context.Context) error { return ValidateRole(ctx, models.RoleEnumInvite) } func ValidateManageInvites(ctx context.Context) error { return ValidateRole(ctx, models.RoleEnumManageInvites) } func ValidateAdmin(ctx context.Context) error { return ValidateRole(ctx, models.RoleEnumAdmin) } func ValidateOwner(ctx context.Context, userID uuid.UUID) error { user := GetCurrentUser(ctx) if user != nil && user.ID == userID { return nil } return ErrUnauthorized } func ValidateUserOrAdmin(ctx context.Context, userID uuid.UUID) error { if err := ValidateOwner(ctx, userID); err == nil { return nil } return ValidateRole(ctx, models.RoleEnumAdmin) } func ValidateBot(ctx context.Context) error { return ValidateRole(ctx, models.RoleEnumBot) } ================================================ FILE: internal/autocert/autocert.go ================================================ package autocert import ( "context" "crypto/tls" "crypto/x509" "encoding/pem" "net/http" "time" "golang.org/x/crypto/acme/autocert" "github.com/stashapp/stash-box/internal/config" "github.com/stashapp/stash-box/pkg/logger" ) var manager *autocert.Manager var domain string // Init initializes autocert if configured and returns the TLS config. // Returns nil if autocert is not enabled. func Init() *tls.Config { cfg := config.GetAutocertConfig() if cfg == nil { return nil } cache := autocert.DirCache(cfg.CacheDir) domain = cfg.Domain manager = &autocert.Manager{ Prompt: autocert.AcceptTOS, HostPolicy: autocert.HostWhitelist(domain), Cache: cache, Email: cfg.Email, } // Obtain certificate on startup go checkAndRenew() tlsConfig := manager.TLSConfig() tlsConfig.MinVersion = tls.VersionTLS12 return tlsConfig } // HTTPHandler returns the autocert HTTP handler for ACME challenges. // The fallback handler is used for non-ACME requests. func HTTPHandler(fallback http.Handler) http.Handler { if manager == nil { return fallback } return manager.HTTPHandler(fallback) } // CheckAndRenew checks the certificate and renews if needed. // Called by cron job. func CheckAndRenew() { if manager == nil { return } checkAndRenew() } func checkAndRenew() { // Check cache first if data, err := manager.Cache.Get(context.Background(), domain); err == nil { if block, _ := pem.Decode(data); block != nil { if cert, err := x509.ParseCertificate(block.Bytes); err == nil { now := time.Now() daysUntilExpiry := int(cert.NotAfter.Sub(now).Hours() / 24) switch { case now.After(cert.NotAfter): logger.Warnf("Autocert: certificate for %s has expired, renewing...", domain) case daysUntilExpiry <= 30: logger.Infof("Autocert: certificate for %s expires in %d days, renewing...", domain, daysUntilExpiry) default: return } } } } else { logger.Infof("Autocert: obtaining certificate for %s from Let's Encrypt...", domain) } // Trigger certificate acquisition/renewal hello := &tls.ClientHelloInfo{ServerName: domain} cert, err := manager.GetCertificate(hello) if err != nil { logger.Errorf("Autocert: failed to obtain certificate for %s: %v", domain, err) return } if cert != nil && len(cert.Certificate) > 0 { if x509Cert, parseErr := x509.ParseCertificate(cert.Certificate[0]); parseErr == nil { daysUntilExpiry := int(time.Until(x509Cert.NotAfter).Hours() / 24) logger.Infof("Autocert: obtained certificate for %s (expires %s, %d days remaining)", domain, x509Cert.NotAfter.Format("2006-01-02"), daysUntilExpiry) } } } ================================================ FILE: internal/config/config.go ================================================ package config import ( "errors" "time" "github.com/spf13/viper" "github.com/stashapp/stash-box/pkg/utils" ) type S3Config struct { Endpoint string `mapstructure:"endpoint"` Bucket string `mapstructure:"bucket"` AccessKey string `mapstructure:"access_key"` Secret string `mapstructure:"secret"` MaxDimension int `mapstructure:"max_dimension"` UploadHeaders map[string]string `mapstructure:"upload_headers"` } type PostgresConfig struct { MaxOpenConns int `mapstructure:"max_open_conns"` MaxIdleConns int `mapstructure:"max_idle_conns"` ConnMaxLifetime int `mapstructure:"conn_max_lifetime"` } type OTelConfig struct { Endpoint string `mapstructure:"endpoint"` TraceRatio float64 `mapstructure:"trace_ratio"` } type ImageResizeConfig struct { Enabled bool `mapstructure:"enabled"` CachePath string `mapstructure:"cache_path"` MinSize int `mapstructure:"min_size"` } type AutocertConfig struct { Enabled bool `mapstructure:"enabled"` Domain string `mapstructure:"domain"` Email string `mapstructure:"email"` CacheDir string `mapstructure:"cache_dir"` } type config struct { Host string `mapstructure:"host"` Port int `mapstructure:"port"` Database string `mapstructure:"database"` ProfilerPort int `mapstructure:"profiler_port"` HTTPUpgrade bool `mapstructure:"http_upgrade"` IsProduction bool `mapstructure:"is_production"` // Key used to sign JWT tokens JWTSignKey string `mapstructure:"jwt_secret_key"` // Key used for session store SessionStoreKey string `mapstructure:"session_store_key"` // Invite settings RequireInvite bool `mapstructure:"require_invite"` RequireActivation bool `mapstructure:"require_activation"` ActivationExpiry int `mapstructure:"activation_expiry"` EmailCooldown int `mapstructure:"email_cooldown"` DefaultUserRoles []string `mapstructure:"default_user_roles"` // URL link for contributor guidelines for submitting edits GuidelinesURL string `mapstructure:"guidelines_url"` // Number of approved edits before user automatically gets VOTE role VotePromotionThreshold int `mapstructure:"vote_promotion_threshold"` // Number of positive votes required for immediate approval VoteApplicationThreshold int `mapstructure:"vote_application_threshold"` // Duration, in seconds, of the voting period VotingPeriod int `mapstructure:"voting_period"` // Duration, in seconds, of the minimum voting period for destructive edits MinDestructiveVotingPeriod int `mapstructure:"min_destructive_voting_period"` // Interval between checks for completed voting periods VoteCronInterval string `mapstructure:"vote_cron_interval"` // Number of times an edit can be updated by the creator EditUpdateLimit int `mapstructure:"edit_update_limit"` // Require all scene create edits to be submitted via drafts RequireSceneDraft bool `mapstructure:"require_scene_draft"` // Require the TagRole or Admin to edit tags RequireTagRole bool `mapstructure:"require_tag_role"` // Email settings EmailHost string `mapstructure:"email_host"` EmailPort int `mapstructure:"email_port"` EmailUser string `mapstructure:"email_user"` EmailPW string `mapstructure:"email_password"` EmailFrom string `mapstructure:"email_from"` HostURL string `mapstructure:"host_url"` // Image storage settings ImageLocation string `mapstructure:"image_location"` ImageBackend string `mapstructure:"image_backend"` FaviconPath string `mapstructure:"favicon_path"` ImageMaxSize int `mapstructure:"image_max_size"` ImageJpegQuality int `mapstructure:"image_jpeg_quality"` // Logging options LogFile string `mapstructure:"logFile"` UserLogFile string `mapstructure:"userLogFile"` LogOut bool `mapstructure:"logOut"` LogLevel string `mapstructure:"logLevel"` S3 struct { S3Config `mapstructure:",squash"` } Postgres struct { PostgresConfig `mapstructure:",squash"` } OTel struct { OTelConfig `mapstructure:",squash"` } // revive:disable-next-line Image_Resizing struct { ImageResizeConfig `mapstructure:",squash"` } Autocert struct { AutocertConfig `mapstructure:",squash"` } PHashDistance int `mapstructure:"phash_distance"` Title string `mapstructure:"title"` DraftTimeLimit int `mapstructure:"draft_time_limit"` // Number of days to retain mod audit logs (0 to disable logging) ModAuditRetentionDays int `mapstructure:"mod_audit_retention_days"` CSP string `mapstructure:"csp"` } var JWTSignKey = "jwt_secret_key" var SessionStoreKey = "session_store_key" var Database = "database" type ImageBackendType string const ( FileBackend ImageBackendType = "file" S3Backend ImageBackendType = "s3" ) var defaultUserRoles = []string{"READ", "VOTE", "EDIT"} var C = &config{ RequireInvite: true, RequireActivation: false, ActivationExpiry: 2 * 60 * 60, EmailCooldown: 5 * 60, EmailPort: 25, ImageBackend: string(FileBackend), PHashDistance: 0, VoteApplicationThreshold: 3, VotePromotionThreshold: 10, VoteCronInterval: "5m", VotingPeriod: 345600, MinDestructiveVotingPeriod: 172800, DraftTimeLimit: 86400, EditUpdateLimit: 1, RequireSceneDraft: false, RequireTagRole: false, ModAuditRetentionDays: 30, } func GetDatabasePath() string { return C.Database } func GetHost() string { return C.Host } func GetPort() int { return C.Port } func GetProfilerPort() *int { if C.ProfilerPort == 0 { return nil } return &C.ProfilerPort } func GetJWTSignKey() []byte { return []byte(C.JWTSignKey) } func GetSessionStoreKey() []byte { return []byte(C.SessionStoreKey) } func GetHTTPUpgrade() bool { return C.HTTPUpgrade } func GetIsProduction() bool { return C.IsProduction } // GetRequireInvite returns true if new users cannot register without an invite // key. func GetRequireInvite() bool { return C.RequireInvite } // GetRequireActivation returns true if new users must validate their email address // via activation to create an account. func GetRequireActivation() bool { return C.RequireActivation } // GetActivationExpiry returns the duration before an activation email expires. func GetActivationExpiry() time.Duration { return time.Duration(C.ActivationExpiry * int(time.Second)) } // GetEmailCooldown returns the duration before a second activation email may // be generated. func GetEmailCooldown() time.Duration { return time.Duration(C.EmailCooldown * int(time.Second)) } // GetDefaultUserRoles returns the default roles assigned to a new user // when created via registration. func GetDefaultUserRoles() []string { if len(C.DefaultUserRoles) == 0 { return defaultUserRoles } return C.DefaultUserRoles } func GetEmailHost() string { return C.EmailHost } func GetEmailPort() int { return C.EmailPort } func GetEmailUser() string { return C.EmailUser } func GetEmailPassword() string { return C.EmailPW } func GetEmailFrom() string { return C.EmailFrom } func GetHostURL() string { return C.HostURL } func GetGuidelinesURL() string { return C.GuidelinesURL } // GetImageLocation returns the path of where to locally store images. func GetImageLocation() string { return C.ImageLocation } // GetImageBackend returns the backend used to store images. func GetImageBackend() ImageBackendType { return ImageBackendType(C.ImageBackend) } func GetS3Config() *S3Config { return &C.S3.S3Config } func GetImageResizeConfig() *ImageResizeConfig { return &C.Image_Resizing.ImageResizeConfig } func GetOTelConfig() *OTelConfig { if C.OTel.Endpoint != "" { return &C.OTel.OTelConfig } return nil } func GetAutocertConfig() *AutocertConfig { if C.Autocert.Enabled { return &C.Autocert.AutocertConfig } return nil } func GetMissingAutocertSettings() []string { if !C.Autocert.Enabled { return nil } missing := []string{} if C.Autocert.Domain == "" { missing = append(missing, "domain") } if C.Autocert.Email == "" { missing = append(missing, "email") } if C.Autocert.CacheDir == "" { missing = append(missing, "cache_dir") } return missing } // ValidateImageLocation returns an error is image_location is not set. func ValidateImageLocation() error { if C.ImageLocation == "" { return errors.New("ImageLocation not set") } return nil } func GetImageMaxSize() *int { size := C.ImageMaxSize if size == 0 { return nil } return &size } func GetImageJpegQuality() int { if C.ImageJpegQuality <= 0 || C.ImageJpegQuality > 100 { return 75 } return C.ImageJpegQuality } // GetLogFile returns the filename of the file to output logs to. // An empty string means that file logging will be disabled. func GetLogFile() string { return C.LogFile } // GetUserLogFile returns the filename of the file to output user operation // logs to. // An empty string means that user operation logging will be output to stderr. func GetUserLogFile() string { return C.UserLogFile } // GetLogOut returns true if logging should be output to the terminal // in addition to writing to a log file. Logging will be output to the // terminal if file logging is disabled. Defaults to true. func GetLogOut() bool { return C.LogOut } // GetLogLevel returns the lowest log level to write to the log. // Should be one of "Debug", "Info", "Warning", "Error" func GetLogLevel() string { const defaultValue = "Info" value := C.LogLevel if value != "Debug" && value != "Info" && value != "Warning" && value != "Error" { value = defaultValue } return value } func GetPHashDistance() int { return C.PHashDistance } func InitializeDefaults() error { // generate some api keys const apiKeyLength = 32 if viper.GetString(JWTSignKey) == "" { signKey, err := utils.GenerateRandomKey(apiKeyLength) if err != nil { return err } viper.Set(JWTSignKey, signKey) } if viper.GetString(SessionStoreKey) == "" { sessionStoreKey, err := utils.GenerateRandomKey(apiKeyLength) if err != nil { return err } viper.Set(SessionStoreKey, sessionStoreKey) } if viper.GetString(Database) == "" { viper.Set(Database, GetDefaultDatabaseFilePath()) } return viper.WriteConfig() } // Unmarshal config func Initialize() error { return viper.Unmarshal(&C) } func GetMissingEmailSettings() []string { if !GetRequireActivation() { return nil } missing := []string{} if GetEmailFrom() == "" { missing = append(missing, "EmailFrom") } if GetEmailHost() == "" { missing = append(missing, "EmailHost") } if GetHostURL() == "" { missing = append(missing, "HostURL") } return missing } func GetVotePromotionThreshold() *int { if C.VotePromotionThreshold == 0 { return nil } return &C.VotePromotionThreshold } func GetVoteApplicationThreshold() int { return C.VoteApplicationThreshold } func GetVotingPeriod() int { return C.VotingPeriod } func GetMinDestructiveVotingPeriod() int { return C.MinDestructiveVotingPeriod } func GetVoteCronInterval() string { return C.VoteCronInterval } func GetEditUpdateLimit() int { return C.EditUpdateLimit } func GetRequireSceneDraft() bool { return C.RequireSceneDraft } func GetRequireTagRole() bool { return C.RequireTagRole } func GetTitle() string { if C.Title == "" { return "Stash-Box" } return C.Title } func GetFaviconPath() (*string, error) { if len(C.FaviconPath) == 0 { return nil, errors.New("favicon_path not set") } return &C.FaviconPath, nil } func GetDraftTimeLimit() int { return C.DraftTimeLimit } func GetModAuditRetentionDays() int { return C.ModAuditRetentionDays } func GetMaxOpenConns() int { if C.Postgres.MaxOpenConns == 0 { return 25 } return C.Postgres.MaxOpenConns } func GetMaxIdleConns() int { if C.Postgres.MaxIdleConns == 0 { return 10 } return C.Postgres.MaxIdleConns } func GetConnMaxLifetime() int { return C.Postgres.MaxIdleConns } func GetCSP() string { return C.CSP } ================================================ FILE: internal/config/paths.go ================================================ package config import ( "path/filepath" ) func GetConfigDirectory() string { return "." } func GetDefaultDatabaseFilePath() string { return "postgres@localhost/stash-box?sslmode=disable" } func GetConfigName() string { return "stash-box-config" } func GetDefaultConfigFilePath() string { return filepath.Join(GetConfigDirectory(), GetConfigName()+".yml") } func GetSSLKey() string { return filepath.Join(GetConfigDirectory(), "stash-box.key") } func GetSSLCert() string { return filepath.Join(GetConfigDirectory(), "stash-box.crt") } ================================================ FILE: internal/converter/converter.go ================================================ package converter import ( "encoding/json" "time" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/config" "github.com/stashapp/stash-box/internal/converter/gen" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/internal/queries" "github.com/stashapp/stash-box/pkg/logger" ) // Package-level converter instances (stateless, created once) var ( modelConverter = &gen.ModelConverterImpl{} inputConverter = &gen.InputConverterImpl{} createParamsConverter = &gen.CreateParamsConverterImpl{} updateParamsConverter = &gen.UpdateParamsConverterImpl{} ) // ImageToModel converts a queries.Image to a models.Image func ImageToModel(i queries.Image) models.Image { return modelConverter.ConvertImage(i) } func ImageToModelPtr(i queries.Image) *models.Image { image := ImageToModel(i) return &image } // ImagesToModels converts a slice of queries.Image to a slice of models.Image func ImagesToModels(images []queries.Image) []models.Image { return modelConverter.ConvertImages(images) } // PerformerToModel converts a queries.Performer to a models.Performer func PerformerToModel(p queries.Performer) models.Performer { return modelConverter.ConvertPerformer(p) } func PerformerToModelPtr(p queries.Performer) *models.Performer { performer := PerformerToModel(p) return &performer } // SceneToModel converts a queries.Scene to a models.Scene func SceneToModel(s queries.Scene) models.Scene { return modelConverter.ConvertScene(s) } func SceneToModelPtr(s queries.Scene) *models.Scene { scene := SceneToModel(s) return &scene } // SiteToModel converts a queries.Site to a models.Site func SiteToModel(s queries.Site) models.Site { return modelConverter.ConvertSite(s) } func SiteToModelPtr(s queries.Site) *models.Site { site := SiteToModel(s) return &site } // StudioToModel converts a queries.Studio to a models.Studio func StudioToModel(s queries.Studio) models.Studio { return modelConverter.ConvertStudio(s) } func StudioToModelPtr(s queries.Studio) *models.Studio { studio := StudioToModel(s) return &studio } // TagCategoryToModel converts a queries.TagCategory to a models.TagCategory func TagCategoryToModel(tc queries.TagCategory) models.TagCategory { return modelConverter.ConvertTagCategory(tc) } func TagCategoryToModelPtr(tc queries.TagCategory) *models.TagCategory { tagCategory := TagCategoryToModel(tc) return &tagCategory } // TagToModel converts a queries.Tag to a models.Tag func TagToModel(t queries.Tag) models.Tag { return modelConverter.ConvertTag(t) } func TagToModelPtr(t queries.Tag) *models.Tag { tag := TagToModel(t) return &tag } // UserTokenToModel converts a queries.UserToken to a models.UserToken func UserTokenToModel(ut queries.UserToken) models.UserToken { return modelConverter.ConvertUserToken(ut) } func UserTokenToModelPtr(ut queries.UserToken) *models.UserToken { userToken := UserTokenToModel(ut) return &userToken } // SceneDraftInputToSceneDraft converts a models.SceneDraftInput to a models.SceneDraft func SceneDraftInputToSceneDraft(input models.SceneDraftInput) models.SceneDraft { return inputConverter.ConvertSceneDraftInput(input) } // EditToModel converts a queries.Edit to a models.Edit func EditToModel(e queries.Edit) models.Edit { return modelConverter.ConvertEdit(e) } func EditToModelPtr(e queries.Edit) *models.Edit { edit := EditToModel(e) return &edit } // EditsToModels converts []queries.Edit to []models.Edit func EditsToModels(edits []queries.Edit) []models.Edit { return modelConverter.ConvertEdits(edits) } // EditVoteToModel converts a queries.EditVote to a models.EditVote func EditVoteToModel(ec queries.EditVote) models.EditVote { return modelConverter.ConvertEditVote(ec) } // EditCommentToModel converts a queries.EditComment to a models.EditComment func EditCommentToModel(ec queries.EditComment) models.EditComment { return modelConverter.ConvertEditComment(ec) } func EditCommentToModelPtr(ec queries.EditComment) *models.EditComment { editComment := EditCommentToModel(ec) return &editComment } // TagToCreateParams converts a models.Tag to a queries.CreateTagParams func TagToCreateParams(t models.Tag) queries.CreateTagParams { return createParamsConverter.ConvertTagToCreateParams(t) } // TagToUpdateParams converts a models.Tag to a queries.UpdateTagParams func TagToUpdateParams(t models.Tag) queries.UpdateTagParams { return updateParamsConverter.ConvertTagToUpdateParams(t) } // StudioToCreateParams converts a models.Studio to a queries.CreateStudioParams func StudioToCreateParams(s models.Studio) queries.CreateStudioParams { return createParamsConverter.ConvertStudioToCreateParams(s) } // StudioToUpdateParams converts a models.Studio to a queries.UpdateStudioParams func StudioToUpdateParams(s models.Studio) queries.UpdateStudioParams { return updateParamsConverter.ConvertStudioToUpdateParams(s) } // SceneToCreateParams converts a models.Scene to a queries.CreateSceneParams func SceneToCreateParams(s models.Scene) queries.CreateSceneParams { return createParamsConverter.ConvertSceneToCreateParams(s) } // SceneToUpdateParams converts a models.Scene to a queries.UpdateSceneParams func SceneToUpdateParams(s models.Scene) queries.UpdateSceneParams { return updateParamsConverter.ConvertSceneToUpdateParams(s) } // BodyModInputToModel converts []models.BodyModificationInput to []models.BodyModification func BodyModInputToModel(inputs []models.BodyModificationInput) []models.BodyModification { return inputConverter.ConvertBodyModInputSlice(inputs) } // PerformerToCreateParams converts a models.Performer to a queries.CreatePerformerParams func PerformerToCreateParams(p models.Performer) queries.CreatePerformerParams { return createParamsConverter.ConvertPerformerToCreateParams(p) } // PerformerToUpdateParams converts a models.Performer to a queries.UpdatePerformerParams func PerformerToUpdateParams(p models.Performer) queries.UpdatePerformerParams { return updateParamsConverter.ConvertPerformerToUpdateParams(p) } // EditToUpdateParams converts a models.Edit to a queries.UpdateEditParams func EditToUpdateParams(e models.Edit) queries.UpdateEditParams { return updateParamsConverter.ConvertEditToUpdateParams(e) } // EditToCreateParams converts a models.Edit to a queries.CreateEditParams func EditToCreateParams(e models.Edit) queries.CreateEditParams { return createParamsConverter.ConvertEditToCreateParams(e) } // EditCommentToCreateParams converts a models.EditComment to a queries.CreateEditCommentParams func EditCommentToCreateParams(ec models.EditComment) queries.CreateEditCommentParams { return createParamsConverter.ConvertEditCommentToCreateParams(ec) } // UserToModel converts a queries.User to a models.User func UserToModel(u queries.User) models.User { return modelConverter.ConvertUser(u) } func UserToModelPtr(u queries.User) *models.User { user := UserToModel(u) return &user } // PerformerCreateInputToPerformer converts a models.PerformerCreateInput to a models.Performer func PerformerCreateInputToPerformer(input models.PerformerCreateInput) models.Performer { return models.Performer{ Name: input.Name, Disambiguation: input.Disambiguation, Gender: input.Gender, BirthDate: input.Birthdate, DeathDate: input.Deathdate, Ethnicity: input.Ethnicity, Country: input.Country, EyeColor: input.EyeColor, HairColor: input.HairColor, Height: input.Height, CupSize: input.CupSize, BandSize: input.BandSize, WaistSize: input.WaistSize, HipSize: input.HipSize, BreastType: input.BreastType, CareerStartYear: input.CareerStartYear, CareerEndYear: input.CareerEndYear, } } // UpdatePerformerFromUpdateInput updates an existing models.Performer with data from models.PerformerUpdateInput func UpdatePerformerFromUpdateInput(performer *models.Performer, input models.PerformerUpdateInput) { if input.Name != nil { performer.Name = *input.Name } if input.Disambiguation != nil { performer.Disambiguation = input.Disambiguation } if input.Gender != nil { performer.Gender = input.Gender } if input.Birthdate != nil { performer.BirthDate = input.Birthdate } if input.Deathdate != nil { performer.DeathDate = input.Deathdate } if input.Ethnicity != nil { performer.Ethnicity = input.Ethnicity } if input.Country != nil { performer.Country = input.Country } if input.EyeColor != nil { performer.EyeColor = input.EyeColor } if input.HairColor != nil { performer.HairColor = input.HairColor } if input.Height != nil { performer.Height = input.Height } if input.CupSize != nil { performer.CupSize = input.CupSize } if input.BandSize != nil { performer.BandSize = input.BandSize } if input.WaistSize != nil { performer.WaistSize = input.WaistSize } if input.HipSize != nil { performer.HipSize = input.HipSize } if input.BreastType != nil { performer.BreastType = input.BreastType } if input.CareerStartYear != nil { performer.CareerStartYear = input.CareerStartYear } if input.CareerEndYear != nil { performer.CareerEndYear = input.CareerEndYear } } // SceneCreateInputToScene converts a models.SceneCreateInput to a models.Scene func SceneCreateInputToScene(input models.SceneCreateInput) models.Scene { var studioID uuid.NullUUID if input.StudioID != nil { studioID = uuid.NullUUID{UUID: *input.StudioID, Valid: true} } return models.Scene{ Title: input.Title, Details: input.Details, Date: &input.Date, ProductionDate: input.ProductionDate, StudioID: studioID, Duration: input.Duration, Director: input.Director, Code: input.Code, } } // UpdateSceneFromUpdateInput updates an existing models.Scene with data from models.SceneUpdateInput func UpdateSceneFromUpdateInput(scene *models.Scene, input models.SceneUpdateInput) { if input.Title != nil { scene.Title = input.Title } if input.Details != nil { scene.Details = input.Details } if input.Date != nil { scene.Date = input.Date } if input.ProductionDate != nil { scene.ProductionDate = input.ProductionDate } if input.StudioID != nil { scene.StudioID = uuid.NullUUID{UUID: *input.StudioID, Valid: true} } if input.Duration != nil { scene.Duration = input.Duration } if input.Director != nil { scene.Director = input.Director } if input.Code != nil { scene.Code = input.Code } } // SiteCreateInputToSite converts a models.SiteCreateInput to a models.Site func SiteCreateInputToSite(input models.SiteCreateInput) models.Site { validTypes := make([]string, len(input.ValidTypes)) for i, vt := range input.ValidTypes { validTypes[i] = string(vt) } return models.Site{ Name: input.Name, Description: input.Description, URL: input.URL, Regex: input.Regex, ValidTypes: validTypes, } } // SiteToCreateParams converts a models.Site to a queries.CreateSiteParams func SiteToCreateParams(s models.Site) queries.CreateSiteParams { return createParamsConverter.ConvertSiteToCreateParams(s) } // SiteToUpdateParams converts a models.Site to a queries.UpdateSiteParams func SiteToUpdateParams(s models.Site) queries.UpdateSiteParams { return updateParamsConverter.ConvertSiteToUpdateParams(s) } // UpdateSiteFromUpdateInput updates an existing models.Site with data from models.SiteUpdateInput func UpdateSiteFromUpdateInput(site *models.Site, input models.SiteUpdateInput) { site.Name = input.Name site.Description = input.Description site.URL = input.URL site.Regex = input.Regex validTypes := make([]string, len(input.ValidTypes)) for i, vt := range input.ValidTypes { validTypes[i] = string(vt) } site.ValidTypes = validTypes } // StudioCreateInputToCreateParams converts a models.StudioCreateInput to a queries.CreateStudioParams func StudioCreateInputToCreateParams(input models.StudioCreateInput) (queries.CreateStudioParams, error) { id, err := uuid.NewV7() if err != nil { return queries.CreateStudioParams{}, err } var parentStudioID uuid.NullUUID if input.ParentID != nil { parentStudioID = uuid.NullUUID{UUID: *input.ParentID, Valid: true} } return queries.CreateStudioParams{ ID: id, Name: input.Name, ParentStudioID: parentStudioID, }, nil } // UpdateStudioFromUpdateInput applies changes from models.StudioUpdateInput to queries.Studio and returns queries.UpdateStudioParams func UpdateStudioFromUpdateInput(studio queries.Studio, input models.StudioUpdateInput) queries.UpdateStudioParams { // Start with existing studio values name := studio.Name parentStudioID := studio.ParentStudioID // Apply updates from input if input.Name != nil { name = *input.Name } if input.ParentID != nil { parentStudioID = uuid.NullUUID{UUID: *input.ParentID, Valid: true} } return queries.UpdateStudioParams{ ID: studio.ID, Name: name, ParentStudioID: parentStudioID, } } // TagCategoryCreateInputToCreateParams converts a models.TagCategoryCreateInput to a queries.CreateTagCategoryParams func TagCategoryCreateInputToCreateParams(input models.TagCategoryCreateInput) (queries.CreateTagCategoryParams, error) { id, err := uuid.NewV7() if err != nil { return queries.CreateTagCategoryParams{}, err } return queries.CreateTagCategoryParams{ ID: id, Group: string(input.Group), Name: input.Name, Description: input.Description, }, nil } // UpdateTagCategoryFromUpdateInput applies changes from models.TagCategoryUpdateInput to queries.TagCategory and returns queries.UpdateTagCategoryParams func UpdateTagCategoryFromUpdateInput(tagCategory queries.TagCategory, input models.TagCategoryUpdateInput) queries.UpdateTagCategoryParams { // Start with existing values name := tagCategory.Name group := tagCategory.Group description := tagCategory.Description // Apply updates from input if input.Name != nil { name = *input.Name } if input.Group != nil { group = string(*input.Group) } if input.Description != nil { description = input.Description } return queries.UpdateTagCategoryParams{ ID: tagCategory.ID, Group: group, Name: name, Description: description, } } // TagCreateInputToCreateParams converts a models.TagCreateInput to a queries.CreateTagParams func TagCreateInputToCreateParams(input models.TagCreateInput) (queries.CreateTagParams, error) { id, err := uuid.NewV7() if err != nil { return queries.CreateTagParams{}, err } var categoryID uuid.NullUUID if input.CategoryID != nil { categoryID = uuid.NullUUID{UUID: *input.CategoryID, Valid: true} } return queries.CreateTagParams{ ID: id, Name: input.Name, CategoryID: categoryID, Description: input.Description, }, nil } // UpdateTagFromUpdateInput applies changes from models.TagUpdateInput to queries.Tag and returns queries.UpdateTagParams func UpdateTagFromUpdateInput(tag queries.Tag, input models.TagUpdateInput) queries.UpdateTagParams { // Start with existing values name := tag.Name categoryID := tag.CategoryID // Apply updates from input if input.Name != nil { name = *input.Name } if input.CategoryID != nil { categoryID = uuid.NullUUID{UUID: *input.CategoryID, Valid: true} } return queries.UpdateTagParams{ ID: tag.ID, Name: name, CategoryID: categoryID, Description: input.Description, } } // UserCreateInputToCreateParams converts a models.UserCreateInput to a queries.CreateUserParams func UserCreateInputToCreateParams(input models.UserCreateInput, id uuid.UUID, passwordHash, apiKey string) queries.CreateUserParams { var invitedBy uuid.NullUUID if input.InvitedByID != nil { invitedBy = uuid.NullUUID{UUID: *input.InvitedByID, Valid: true} } return queries.CreateUserParams{ ID: id, Name: input.Name, PasswordHash: passwordHash, Email: input.Email, ApiKey: apiKey, ApiCalls: new(int), InviteTokens: 0, InvitedBy: invitedBy, } } // UpdateUserFromUpdateInput applies changes from models.UserUpdateInput to queries.User and returns queries.UpdateUserParams func UpdateUserFromUpdateInput(user queries.User, input models.UserUpdateInput, passwordHash string) queries.UpdateUserParams { // Start with existing values name := user.Name email := user.Email userPasswordHash := user.PasswordHash // Apply updates from input if input.Name != nil { name = *input.Name } if input.Email != nil { email = *input.Email } if input.Password != nil { userPasswordHash = passwordHash } return queries.UpdateUserParams{ ID: user.ID, Name: name, PasswordHash: userPasswordHash, Email: email, } } // CreateUserTokenParamsFromData creates a queries.CreateUserTokenParams with token expiring based on config func CreateUserTokenParamsFromData(tokenType string, data any) (queries.CreateUserTokenParams, error) { id, err := uuid.NewV4() if err != nil { return queries.CreateUserTokenParams{}, err } dataBytes, err := json.Marshal(data) if err != nil { return queries.CreateUserTokenParams{}, err } now := time.Now() expires := now.Add(config.GetActivationExpiry()) return queries.CreateUserTokenParams{ ID: id, Data: dataBytes, Type: tokenType, CreatedAt: now, ExpiresAt: expires, }, nil } // DraftToModel converts a queries.Draft to a models.Draft func DraftToModel(d queries.Draft) models.Draft { return models.Draft{ ID: d.ID, UserID: d.UserID, Type: d.Type, Data: json.RawMessage(d.Data), CreatedAt: d.CreatedAt, } } func DraftToModelPtr(d queries.Draft) *models.Draft { draft := DraftToModel(d) return &draft } // CreateEditCommentParams creates a queries.CreateEditCommentParams from editID, userID, and comment text func CreateEditCommentParams(editID, userID uuid.UUID, commentText string) (queries.CreateEditCommentParams, error) { id, err := uuid.NewV7() if err != nil { return queries.CreateEditCommentParams{}, err } return queries.CreateEditCommentParams{ ID: id, EditID: editID, UserID: uuid.NullUUID{UUID: userID, Valid: true}, Text: commentText, }, nil } // PerformersToModels converts []queries.Performer to []models.Performer func PerformersToModels(performers []queries.Performer) []models.Performer { return modelConverter.ConvertPerformers(performers) } func ScenesToModels(scenes []queries.Scene) []models.Scene { return modelConverter.ConvertScenes(scenes) } // StudiosToModels converts []queries.Studio to []models.Studio func StudiosToModels(studios []queries.Studio) []models.Studio { return modelConverter.ConvertStudios(studios) } // TagCategoriesToModels converts []queries.TagCategory to []models.TagCategory func TagCategoriesToModels(tagCategories []queries.TagCategory) []models.TagCategory { return modelConverter.ConvertTagCategories(tagCategories) } // TagsToModels converts []queries.Tag to []models.Tag func TagsToModels(tags []queries.Tag) []models.Tag { return modelConverter.ConvertTags(tags) } // EditCommentsToModels converts []queries.EditComment to []models.EditComment func EditCommentsToModels(comments []queries.EditComment) []models.EditComment { return modelConverter.ConvertEditComments(comments) } // EditVotesToModels converts []queries.EditVote to []models.EditVote func EditVotesToModels(votes []queries.EditVote) []models.EditVote { return modelConverter.ConvertEditVotes(votes) } // InviteKeysToModels converts []queries.InviteKey to []models.InviteKey func InviteKeysToModels(keys []queries.InviteKey) []models.InviteKey { return modelConverter.ConvertInviteKeys(keys) } // NotificationsToModels converts []queries.Notification to []models.Notification func NotificationsToModels(notifications []queries.Notification) []models.Notification { return modelConverter.ConvertNotifications(notifications) } // InviteKeyToModel converts a queries.InviteKey to a models.InviteKey func InviteKeyToModel(ik queries.InviteKey) models.InviteKey { var expires *time.Time if ik.ExpireTime != nil { expires = ik.ExpireTime } return models.InviteKey{ ID: ik.ID, GeneratedBy: ik.GeneratedBy, GeneratedAt: ik.GeneratedAt, Uses: ik.Uses, Expires: expires, } } // StringToRoleEnum converts a string to a models.RoleEnum, returns nil if invalid func StringToRoleEnum(s string) *models.RoleEnum { role := models.RoleEnum(s) if !role.IsValid() { logger.Warnf("Invalid role '%s', discarding", s) return nil } return &role } // StringsToRoleEnums converts a slice of strings to a slice of models.RoleEnum, discarding invalid ones func StringsToRoleEnums(strings []string) []models.RoleEnum { var result []models.RoleEnum for _, s := range strings { if role := StringToRoleEnum(s); role != nil { result = append(result, *role) } } return result } // NotificationToModel converts a database notification to a models.Notification func NotificationToModel(dbNotification queries.Notification) models.Notification { notification := models.Notification{ UserID: dbNotification.UserID, Type: models.NotificationEnum(dbNotification.Type), TargetID: dbNotification.ID, CreatedAt: dbNotification.CreatedAt, ReadAt: dbNotification.ReadAt, } return notification } ================================================ FILE: internal/converter/gen/extensions.go ================================================ package gen import ( "time" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/internal/queries" ) // Extend functions for type conversions func ConvertTime(t time.Time) time.Time { return t } func ConvertNullIntToInt(i *int) int { if i != nil { return *i } return 0 } func ConvertNotificationType(t queries.NotificationType) models.NotificationEnum { return models.NotificationEnum(t) } ================================================ FILE: internal/converter/gen/generated.go ================================================ // Code generated by github.com/jmattheis/goverter, DO NOT EDIT. //go:build !goverter package gen import ( "encoding/json" uuid "github.com/gofrs/uuid" models "github.com/stashapp/stash-box/internal/models" queries "github.com/stashapp/stash-box/internal/queries" "time" ) type CreateParamsConverterImpl struct{} func (c *CreateParamsConverterImpl) ConvertEditCommentToCreateParams(source models.EditComment) queries.CreateEditCommentParams { var queriesCreateEditCommentParams queries.CreateEditCommentParams queriesCreateEditCommentParams.ID = c.uuidUUIDToUuidUUID(source.ID) queriesCreateEditCommentParams.EditID = c.uuidUUIDToUuidUUID(source.EditID) queriesCreateEditCommentParams.UserID = c.uuidNullUUIDToUuidNullUUID(source.UserID) queriesCreateEditCommentParams.Text = source.Text return queriesCreateEditCommentParams } func (c *CreateParamsConverterImpl) ConvertEditToCreateParams(source models.Edit) queries.CreateEditParams { var queriesCreateEditParams queries.CreateEditParams queriesCreateEditParams.ID = c.uuidUUIDToUuidUUID(source.ID) queriesCreateEditParams.UserID = c.uuidNullUUIDToUuidNullUUID(source.UserID) queriesCreateEditParams.TargetType = source.TargetType queriesCreateEditParams.Operation = source.Operation queriesCreateEditParams.Data = c.jsonRawMessageToByteList(source.Data) queriesCreateEditParams.Votes = source.VoteCount queriesCreateEditParams.Status = source.Status queriesCreateEditParams.Applied = source.Applied queriesCreateEditParams.Bot = source.Bot return queriesCreateEditParams } func (c *CreateParamsConverterImpl) ConvertPerformerToCreateParams(source models.Performer) queries.CreatePerformerParams { var queriesCreatePerformerParams queries.CreatePerformerParams queriesCreatePerformerParams.ID = c.uuidUUIDToUuidUUID(source.ID) queriesCreatePerformerParams.Name = source.Name if source.Disambiguation != nil { xstring := *source.Disambiguation queriesCreatePerformerParams.Disambiguation = &xstring } if source.Gender != nil { modelsGenderEnum := c.modelsGenderEnumToModelsGenderEnum(*source.Gender) queriesCreatePerformerParams.Gender = &modelsGenderEnum } if source.BirthDate != nil { xstring2 := *source.BirthDate queriesCreatePerformerParams.Birthdate = &xstring2 } if source.Ethnicity != nil { modelsEthnicityEnum := c.modelsEthnicityEnumToModelsEthnicityEnum(*source.Ethnicity) queriesCreatePerformerParams.Ethnicity = &modelsEthnicityEnum } if source.Country != nil { xstring3 := *source.Country queriesCreatePerformerParams.Country = &xstring3 } if source.EyeColor != nil { modelsEyeColorEnum := c.modelsEyeColorEnumToModelsEyeColorEnum(*source.EyeColor) queriesCreatePerformerParams.EyeColor = &modelsEyeColorEnum } if source.HairColor != nil { modelsHairColorEnum := c.modelsHairColorEnumToModelsHairColorEnum(*source.HairColor) queriesCreatePerformerParams.HairColor = &modelsHairColorEnum } if source.Height != nil { xint := *source.Height queriesCreatePerformerParams.Height = &xint } if source.CupSize != nil { xstring4 := *source.CupSize queriesCreatePerformerParams.CupSize = &xstring4 } if source.BandSize != nil { xint2 := *source.BandSize queriesCreatePerformerParams.BandSize = &xint2 } if source.HipSize != nil { xint3 := *source.HipSize queriesCreatePerformerParams.HipSize = &xint3 } if source.WaistSize != nil { xint4 := *source.WaistSize queriesCreatePerformerParams.WaistSize = &xint4 } if source.BreastType != nil { modelsBreastTypeEnum := c.modelsBreastTypeEnumToModelsBreastTypeEnum(*source.BreastType) queriesCreatePerformerParams.BreastType = &modelsBreastTypeEnum } if source.CareerStartYear != nil { xint5 := *source.CareerStartYear queriesCreatePerformerParams.CareerStartYear = &xint5 } if source.CareerEndYear != nil { xint6 := *source.CareerEndYear queriesCreatePerformerParams.CareerEndYear = &xint6 } if source.DeathDate != nil { xstring5 := *source.DeathDate queriesCreatePerformerParams.Deathdate = &xstring5 } return queriesCreatePerformerParams } func (c *CreateParamsConverterImpl) ConvertSceneToCreateParams(source models.Scene) queries.CreateSceneParams { var queriesCreateSceneParams queries.CreateSceneParams queriesCreateSceneParams.ID = c.uuidUUIDToUuidUUID(source.ID) if source.Title != nil { xstring := *source.Title queriesCreateSceneParams.Title = &xstring } if source.Details != nil { xstring2 := *source.Details queriesCreateSceneParams.Details = &xstring2 } if source.Date != nil { xstring3 := *source.Date queriesCreateSceneParams.Date = &xstring3 } if source.ProductionDate != nil { xstring4 := *source.ProductionDate queriesCreateSceneParams.ProductionDate = &xstring4 } queriesCreateSceneParams.StudioID = c.uuidNullUUIDToUuidNullUUID(source.StudioID) if source.Duration != nil { xint := *source.Duration queriesCreateSceneParams.Duration = &xint } if source.Director != nil { xstring5 := *source.Director queriesCreateSceneParams.Director = &xstring5 } if source.Code != nil { xstring6 := *source.Code queriesCreateSceneParams.Code = &xstring6 } return queriesCreateSceneParams } func (c *CreateParamsConverterImpl) ConvertSiteToCreateParams(source models.Site) queries.CreateSiteParams { var queriesCreateSiteParams queries.CreateSiteParams queriesCreateSiteParams.ID = c.uuidUUIDToUuidUUID(source.ID) queriesCreateSiteParams.Name = source.Name if source.Description != nil { xstring := *source.Description queriesCreateSiteParams.Description = &xstring } if source.URL != nil { xstring2 := *source.URL queriesCreateSiteParams.Url = &xstring2 } if source.Regex != nil { xstring3 := *source.Regex queriesCreateSiteParams.Regex = &xstring3 } if source.ValidTypes != nil { queriesCreateSiteParams.ValidTypes = make([]string, len(source.ValidTypes)) for i := 0; i < len(source.ValidTypes); i++ { queriesCreateSiteParams.ValidTypes[i] = source.ValidTypes[i] } } return queriesCreateSiteParams } func (c *CreateParamsConverterImpl) ConvertStudioToCreateParams(source models.Studio) queries.CreateStudioParams { var queriesCreateStudioParams queries.CreateStudioParams queriesCreateStudioParams.ID = c.uuidUUIDToUuidUUID(source.ID) queriesCreateStudioParams.Name = source.Name queriesCreateStudioParams.ParentStudioID = c.uuidNullUUIDToUuidNullUUID(source.ParentStudioID) return queriesCreateStudioParams } func (c *CreateParamsConverterImpl) ConvertTagToCreateParams(source models.Tag) queries.CreateTagParams { var queriesCreateTagParams queries.CreateTagParams queriesCreateTagParams.ID = c.uuidUUIDToUuidUUID(source.ID) queriesCreateTagParams.Name = source.Name queriesCreateTagParams.CategoryID = c.uuidNullUUIDToUuidNullUUID(source.CategoryID) if source.Description != nil { xstring := *source.Description queriesCreateTagParams.Description = &xstring } return queriesCreateTagParams } func (c *CreateParamsConverterImpl) jsonRawMessageToByteList(source json.RawMessage) []uint8 { var byteList []uint8 if source != nil { byteList = make([]uint8, len(source)) for i := 0; i < len(source); i++ { byteList[i] = source[i] } } return byteList } func (c *CreateParamsConverterImpl) modelsBreastTypeEnumToModelsBreastTypeEnum(source models.BreastTypeEnum) models.BreastTypeEnum { var modelsBreastTypeEnum models.BreastTypeEnum switch source { case models.BreastTypeEnumFake: modelsBreastTypeEnum = models.BreastTypeEnumFake case models.BreastTypeEnumNa: modelsBreastTypeEnum = models.BreastTypeEnumNa case models.BreastTypeEnumNatural: modelsBreastTypeEnum = models.BreastTypeEnumNatural default: // ignored } return modelsBreastTypeEnum } func (c *CreateParamsConverterImpl) modelsEthnicityEnumToModelsEthnicityEnum(source models.EthnicityEnum) models.EthnicityEnum { var modelsEthnicityEnum models.EthnicityEnum switch source { case models.EthnicityEnumAsian: modelsEthnicityEnum = models.EthnicityEnumAsian case models.EthnicityEnumBlack: modelsEthnicityEnum = models.EthnicityEnumBlack case models.EthnicityEnumCaucasian: modelsEthnicityEnum = models.EthnicityEnumCaucasian case models.EthnicityEnumIndian: modelsEthnicityEnum = models.EthnicityEnumIndian case models.EthnicityEnumLatin: modelsEthnicityEnum = models.EthnicityEnumLatin case models.EthnicityEnumMiddleEastern: modelsEthnicityEnum = models.EthnicityEnumMiddleEastern case models.EthnicityEnumMixed: modelsEthnicityEnum = models.EthnicityEnumMixed case models.EthnicityEnumOther: modelsEthnicityEnum = models.EthnicityEnumOther default: // ignored } return modelsEthnicityEnum } func (c *CreateParamsConverterImpl) modelsEyeColorEnumToModelsEyeColorEnum(source models.EyeColorEnum) models.EyeColorEnum { var modelsEyeColorEnum models.EyeColorEnum switch source { case models.EyeColorEnumBlue: modelsEyeColorEnum = models.EyeColorEnumBlue case models.EyeColorEnumBrown: modelsEyeColorEnum = models.EyeColorEnumBrown case models.EyeColorEnumGreen: modelsEyeColorEnum = models.EyeColorEnumGreen case models.EyeColorEnumGrey: modelsEyeColorEnum = models.EyeColorEnumGrey case models.EyeColorEnumHazel: modelsEyeColorEnum = models.EyeColorEnumHazel case models.EyeColorEnumRed: modelsEyeColorEnum = models.EyeColorEnumRed default: // ignored } return modelsEyeColorEnum } func (c *CreateParamsConverterImpl) modelsGenderEnumToModelsGenderEnum(source models.GenderEnum) models.GenderEnum { var modelsGenderEnum models.GenderEnum switch source { case models.GenderEnumFemale: modelsGenderEnum = models.GenderEnumFemale case models.GenderEnumIntersex: modelsGenderEnum = models.GenderEnumIntersex case models.GenderEnumMale: modelsGenderEnum = models.GenderEnumMale case models.GenderEnumNonBinary: modelsGenderEnum = models.GenderEnumNonBinary case models.GenderEnumTransgenderFemale: modelsGenderEnum = models.GenderEnumTransgenderFemale case models.GenderEnumTransgenderMale: modelsGenderEnum = models.GenderEnumTransgenderMale default: // ignored } return modelsGenderEnum } func (c *CreateParamsConverterImpl) modelsHairColorEnumToModelsHairColorEnum(source models.HairColorEnum) models.HairColorEnum { var modelsHairColorEnum models.HairColorEnum switch source { case models.HairColorEnumAuburn: modelsHairColorEnum = models.HairColorEnumAuburn case models.HairColorEnumBald: modelsHairColorEnum = models.HairColorEnumBald case models.HairColorEnumBlack: modelsHairColorEnum = models.HairColorEnumBlack case models.HairColorEnumBlonde: modelsHairColorEnum = models.HairColorEnumBlonde case models.HairColorEnumBrunette: modelsHairColorEnum = models.HairColorEnumBrunette case models.HairColorEnumGrey: modelsHairColorEnum = models.HairColorEnumGrey case models.HairColorEnumOther: modelsHairColorEnum = models.HairColorEnumOther case models.HairColorEnumRed: modelsHairColorEnum = models.HairColorEnumRed case models.HairColorEnumVarious: modelsHairColorEnum = models.HairColorEnumVarious case models.HairColorEnumWhite: modelsHairColorEnum = models.HairColorEnumWhite default: // ignored } return modelsHairColorEnum } func (c *CreateParamsConverterImpl) uuidNullUUIDToUuidNullUUID(source uuid.NullUUID) uuid.NullUUID { var uuidNullUUID uuid.NullUUID uuidNullUUID.UUID = c.uuidUUIDToUuidUUID(source.UUID) uuidNullUUID.Valid = source.Valid return uuidNullUUID } func (c *CreateParamsConverterImpl) uuidUUIDToUuidUUID(source uuid.UUID) uuid.UUID { var uuidUUID uuid.UUID for i := 0; i < len(source); i++ { uuidUUID[i] = source[i] } return uuidUUID } type InputConverterImpl struct{} func (c *InputConverterImpl) ConvertBodyModInputSlice(source []models.BodyModificationInput) []models.BodyModification { var modelsBodyModificationList []models.BodyModification if source != nil { modelsBodyModificationList = make([]models.BodyModification, len(source)) for i := 0; i < len(source); i++ { modelsBodyModificationList[i] = c.modelsBodyModificationInputToModelsBodyModification(source[i]) } } return modelsBodyModificationList } func (c *InputConverterImpl) ConvertSceneDraftInput(source models.SceneDraftInput) models.SceneDraft { var modelsSceneDraft models.SceneDraft modelsSceneDraft.ID = c.pUuidUUIDToPUuidUUID(source.ID) if source.Title != nil { xstring := *source.Title modelsSceneDraft.Title = &xstring } if source.Code != nil { xstring2 := *source.Code modelsSceneDraft.Code = &xstring2 } if source.Details != nil { xstring3 := *source.Details modelsSceneDraft.Details = &xstring3 } if source.Director != nil { xstring4 := *source.Director modelsSceneDraft.Director = &xstring4 } if source.Urls != nil { modelsSceneDraft.URLs = make([]string, len(source.Urls)) for i := 0; i < len(source.Urls); i++ { modelsSceneDraft.URLs[i] = source.Urls[i] } } if source.Date != nil { xstring5 := *source.Date modelsSceneDraft.Date = &xstring5 } if source.ProductionDate != nil { xstring6 := *source.ProductionDate modelsSceneDraft.ProductionDate = &xstring6 } modelsSceneDraft.Studio = c.pModelsDraftEntityInputToPModelsDraftEntity(source.Studio) if source.Performers != nil { modelsSceneDraft.Performers = make([]models.DraftEntity, len(source.Performers)) for j := 0; j < len(source.Performers); j++ { modelsSceneDraft.Performers[j] = c.modelsDraftEntityInputToModelsDraftEntity(source.Performers[j]) } } if source.Fingerprints != nil { modelsSceneDraft.Fingerprints = make([]models.DraftFingerprint, len(source.Fingerprints)) for k := 0; k < len(source.Fingerprints); k++ { modelsSceneDraft.Fingerprints[k] = c.modelsFingerprintInputToModelsDraftFingerprint(source.Fingerprints[k]) } } return modelsSceneDraft } func (c *InputConverterImpl) modelsBodyModificationInputToModelsBodyModification(source models.BodyModificationInput) models.BodyModification { var modelsBodyModification models.BodyModification modelsBodyModification.Location = source.Location if source.Description != nil { xstring := *source.Description modelsBodyModification.Description = &xstring } return modelsBodyModification } func (c *InputConverterImpl) modelsDraftEntityInputToModelsDraftEntity(source models.DraftEntityInput) models.DraftEntity { var modelsDraftEntity models.DraftEntity modelsDraftEntity.Name = source.Name modelsDraftEntity.ID = c.pUuidUUIDToPUuidUUID(source.ID) return modelsDraftEntity } func (c *InputConverterImpl) modelsFingerprintAlgorithmToModelsFingerprintAlgorithm(source models.FingerprintAlgorithm) models.FingerprintAlgorithm { var modelsFingerprintAlgorithm models.FingerprintAlgorithm switch source { case models.FingerprintAlgorithmMd5: modelsFingerprintAlgorithm = models.FingerprintAlgorithmMd5 case models.FingerprintAlgorithmOshash: modelsFingerprintAlgorithm = models.FingerprintAlgorithmOshash case models.FingerprintAlgorithmPhash: modelsFingerprintAlgorithm = models.FingerprintAlgorithmPhash default: // ignored } return modelsFingerprintAlgorithm } func (c *InputConverterImpl) modelsFingerprintInputToModelsDraftFingerprint(source models.FingerprintInput) models.DraftFingerprint { var modelsDraftFingerprint models.DraftFingerprint modelsDraftFingerprint.Hash = models.FingerprintHash(source.Hash) modelsDraftFingerprint.Algorithm = c.modelsFingerprintAlgorithmToModelsFingerprintAlgorithm(source.Algorithm) modelsDraftFingerprint.Duration = source.Duration return modelsDraftFingerprint } func (c *InputConverterImpl) pModelsDraftEntityInputToPModelsDraftEntity(source *models.DraftEntityInput) *models.DraftEntity { var pModelsDraftEntity *models.DraftEntity if source != nil { var modelsDraftEntity models.DraftEntity modelsDraftEntity.Name = (*source).Name modelsDraftEntity.ID = c.pUuidUUIDToPUuidUUID((*source).ID) pModelsDraftEntity = &modelsDraftEntity } return pModelsDraftEntity } func (c *InputConverterImpl) pUuidUUIDToPUuidUUID(source *uuid.UUID) *uuid.UUID { var pUuidUUID *uuid.UUID if source != nil { uuidUUID := c.uuidUUIDToUuidUUID2((*source)) pUuidUUID = &uuidUUID } return pUuidUUID } func (c *InputConverterImpl) uuidUUIDToUuidUUID2(source uuid.UUID) uuid.UUID { var uuidUUID uuid.UUID for i := 0; i < len(source); i++ { uuidUUID[i] = source[i] } return uuidUUID } type ModelConverterImpl struct{} func (c *ModelConverterImpl) ConvertEdit(source queries.Edit) models.Edit { var modelsEdit models.Edit modelsEdit.ID = c.uuidUUIDToUuidUUID3(source.ID) modelsEdit.UserID = c.uuidNullUUIDToUuidNullUUID2(source.UserID) modelsEdit.TargetType = source.TargetType modelsEdit.Operation = source.Operation modelsEdit.VoteCount = source.Votes modelsEdit.Status = source.Status modelsEdit.Applied = source.Applied modelsEdit.Data = c.byteListToJsonRawMessage(source.Data) modelsEdit.Bot = source.Bot modelsEdit.CreatedAt = ConvertTime(source.CreatedAt) modelsEdit.UpdateCount = source.UpdateCount modelsEdit.UpdatedAt = c.pTimeTimeToPTimeTime(source.UpdatedAt) modelsEdit.ClosedAt = c.pTimeTimeToPTimeTime(source.ClosedAt) return modelsEdit } func (c *ModelConverterImpl) ConvertEditComment(source queries.EditComment) models.EditComment { var modelsEditComment models.EditComment modelsEditComment.ID = c.uuidUUIDToUuidUUID3(source.ID) modelsEditComment.EditID = c.uuidUUIDToUuidUUID3(source.EditID) modelsEditComment.UserID = c.uuidNullUUIDToUuidNullUUID2(source.UserID) modelsEditComment.CreatedAt = ConvertTime(source.CreatedAt) modelsEditComment.Text = source.Text return modelsEditComment } func (c *ModelConverterImpl) ConvertEditComments(source []queries.EditComment) []models.EditComment { var modelsEditCommentList []models.EditComment if source != nil { modelsEditCommentList = make([]models.EditComment, len(source)) for i := 0; i < len(source); i++ { modelsEditCommentList[i] = c.ConvertEditComment(source[i]) } } return modelsEditCommentList } func (c *ModelConverterImpl) ConvertEditVote(source queries.EditVote) models.EditVote { var modelsEditVote models.EditVote modelsEditVote.EditID = c.uuidUUIDToUuidUUID3(source.EditID) modelsEditVote.UserID = c.uuidUUIDToUuidUUID3(source.UserID) modelsEditVote.CreatedAt = ConvertTime(source.CreatedAt) modelsEditVote.Vote = source.Vote return modelsEditVote } func (c *ModelConverterImpl) ConvertEditVotes(source []queries.EditVote) []models.EditVote { var modelsEditVoteList []models.EditVote if source != nil { modelsEditVoteList = make([]models.EditVote, len(source)) for i := 0; i < len(source); i++ { modelsEditVoteList[i] = c.ConvertEditVote(source[i]) } } return modelsEditVoteList } func (c *ModelConverterImpl) ConvertEdits(source []queries.Edit) []models.Edit { var modelsEditList []models.Edit if source != nil { modelsEditList = make([]models.Edit, len(source)) for i := 0; i < len(source); i++ { modelsEditList[i] = c.ConvertEdit(source[i]) } } return modelsEditList } func (c *ModelConverterImpl) ConvertImage(source queries.Image) models.Image { var modelsImage models.Image modelsImage.ID = c.uuidUUIDToUuidUUID3(source.ID) if source.Url != nil { xstring := *source.Url modelsImage.RemoteURL = &xstring } modelsImage.Checksum = source.Checksum modelsImage.Width = source.Width modelsImage.Height = source.Height return modelsImage } func (c *ModelConverterImpl) ConvertImages(source []queries.Image) []models.Image { var modelsImageList []models.Image if source != nil { modelsImageList = make([]models.Image, len(source)) for i := 0; i < len(source); i++ { modelsImageList[i] = c.ConvertImage(source[i]) } } return modelsImageList } func (c *ModelConverterImpl) ConvertInviteKey(source queries.InviteKey) models.InviteKey { var modelsInviteKey models.InviteKey modelsInviteKey.ID = c.uuidUUIDToUuidUUID3(source.ID) if source.Uses != nil { xint := *source.Uses modelsInviteKey.Uses = &xint } modelsInviteKey.GeneratedBy = c.uuidUUIDToUuidUUID3(source.GeneratedBy) modelsInviteKey.GeneratedAt = ConvertTime(source.GeneratedAt) modelsInviteKey.Expires = c.pTimeTimeToPTimeTime(source.ExpireTime) return modelsInviteKey } func (c *ModelConverterImpl) ConvertInviteKeys(source []queries.InviteKey) []models.InviteKey { var modelsInviteKeyList []models.InviteKey if source != nil { modelsInviteKeyList = make([]models.InviteKey, len(source)) for i := 0; i < len(source); i++ { modelsInviteKeyList[i] = c.ConvertInviteKey(source[i]) } } return modelsInviteKeyList } func (c *ModelConverterImpl) ConvertNotification(source queries.Notification) models.Notification { var modelsNotification models.Notification modelsNotification.UserID = c.uuidUUIDToUuidUUID3(source.UserID) modelsNotification.Type = ConvertNotificationType(source.Type) modelsNotification.TargetID = c.uuidUUIDToUuidUUID3(source.ID) modelsNotification.CreatedAt = ConvertTime(source.CreatedAt) modelsNotification.ReadAt = c.pTimeTimeToPTimeTime(source.ReadAt) return modelsNotification } func (c *ModelConverterImpl) ConvertNotifications(source []queries.Notification) []models.Notification { var modelsNotificationList []models.Notification if source != nil { modelsNotificationList = make([]models.Notification, len(source)) for i := 0; i < len(source); i++ { modelsNotificationList[i] = c.ConvertNotification(source[i]) } } return modelsNotificationList } func (c *ModelConverterImpl) ConvertPerformer(source queries.Performer) models.Performer { var modelsPerformer models.Performer modelsPerformer.ID = c.uuidUUIDToUuidUUID3(source.ID) modelsPerformer.Name = source.Name if source.Disambiguation != nil { xstring := *source.Disambiguation modelsPerformer.Disambiguation = &xstring } if source.Gender != nil { modelsGenderEnum := c.modelsGenderEnumToModelsGenderEnum2(*source.Gender) modelsPerformer.Gender = &modelsGenderEnum } if source.Birthdate != nil { xstring2 := *source.Birthdate modelsPerformer.BirthDate = &xstring2 } if source.Deathdate != nil { xstring3 := *source.Deathdate modelsPerformer.DeathDate = &xstring3 } if source.Ethnicity != nil { modelsEthnicityEnum := c.modelsEthnicityEnumToModelsEthnicityEnum2(*source.Ethnicity) modelsPerformer.Ethnicity = &modelsEthnicityEnum } if source.Country != nil { xstring4 := *source.Country modelsPerformer.Country = &xstring4 } if source.EyeColor != nil { modelsEyeColorEnum := c.modelsEyeColorEnumToModelsEyeColorEnum2(*source.EyeColor) modelsPerformer.EyeColor = &modelsEyeColorEnum } if source.HairColor != nil { modelsHairColorEnum := c.modelsHairColorEnumToModelsHairColorEnum2(*source.HairColor) modelsPerformer.HairColor = &modelsHairColorEnum } if source.Height != nil { xint := *source.Height modelsPerformer.Height = &xint } if source.CupSize != nil { xstring5 := *source.CupSize modelsPerformer.CupSize = &xstring5 } if source.BandSize != nil { xint2 := *source.BandSize modelsPerformer.BandSize = &xint2 } if source.WaistSize != nil { xint3 := *source.WaistSize modelsPerformer.WaistSize = &xint3 } if source.HipSize != nil { xint4 := *source.HipSize modelsPerformer.HipSize = &xint4 } if source.BreastType != nil { modelsBreastTypeEnum := c.modelsBreastTypeEnumToModelsBreastTypeEnum2(*source.BreastType) modelsPerformer.BreastType = &modelsBreastTypeEnum } if source.CareerStartYear != nil { xint5 := *source.CareerStartYear modelsPerformer.CareerStartYear = &xint5 } if source.CareerEndYear != nil { xint6 := *source.CareerEndYear modelsPerformer.CareerEndYear = &xint6 } modelsPerformer.Deleted = source.Deleted modelsPerformer.Created = ConvertTime(source.CreatedAt) modelsPerformer.Updated = ConvertTime(source.UpdatedAt) return modelsPerformer } func (c *ModelConverterImpl) ConvertPerformers(source []queries.Performer) []models.Performer { var modelsPerformerList []models.Performer if source != nil { modelsPerformerList = make([]models.Performer, len(source)) for i := 0; i < len(source); i++ { modelsPerformerList[i] = c.ConvertPerformer(source[i]) } } return modelsPerformerList } func (c *ModelConverterImpl) ConvertScene(source queries.Scene) models.Scene { var modelsScene models.Scene modelsScene.ID = c.uuidUUIDToUuidUUID3(source.ID) if source.Title != nil { xstring := *source.Title modelsScene.Title = &xstring } if source.Details != nil { xstring2 := *source.Details modelsScene.Details = &xstring2 } if source.Date != nil { xstring3 := *source.Date modelsScene.Date = &xstring3 } if source.ProductionDate != nil { xstring4 := *source.ProductionDate modelsScene.ProductionDate = &xstring4 } modelsScene.StudioID = c.uuidNullUUIDToUuidNullUUID2(source.StudioID) modelsScene.CreatedAt = ConvertTime(source.CreatedAt) modelsScene.UpdatedAt = ConvertTime(source.UpdatedAt) if source.Duration != nil { xint := *source.Duration modelsScene.Duration = &xint } if source.Director != nil { xstring5 := *source.Director modelsScene.Director = &xstring5 } if source.Code != nil { xstring6 := *source.Code modelsScene.Code = &xstring6 } modelsScene.Deleted = source.Deleted return modelsScene } func (c *ModelConverterImpl) ConvertScenes(source []queries.Scene) []models.Scene { var modelsSceneList []models.Scene if source != nil { modelsSceneList = make([]models.Scene, len(source)) for i := 0; i < len(source); i++ { modelsSceneList[i] = c.ConvertScene(source[i]) } } return modelsSceneList } func (c *ModelConverterImpl) ConvertSite(source queries.Site) models.Site { var modelsSite models.Site modelsSite.ID = c.uuidUUIDToUuidUUID3(source.ID) modelsSite.Name = source.Name if source.Description != nil { xstring := *source.Description modelsSite.Description = &xstring } if source.Url != nil { xstring2 := *source.Url modelsSite.URL = &xstring2 } if source.Regex != nil { xstring3 := *source.Regex modelsSite.Regex = &xstring3 } if source.ValidTypes != nil { modelsSite.ValidTypes = make([]string, len(source.ValidTypes)) for i := 0; i < len(source.ValidTypes); i++ { modelsSite.ValidTypes[i] = source.ValidTypes[i] } } modelsSite.CreatedAt = ConvertTime(source.CreatedAt) modelsSite.UpdatedAt = ConvertTime(source.UpdatedAt) return modelsSite } func (c *ModelConverterImpl) ConvertStudio(source queries.Studio) models.Studio { var modelsStudio models.Studio modelsStudio.ID = c.uuidUUIDToUuidUUID3(source.ID) modelsStudio.Name = source.Name modelsStudio.ParentStudioID = c.uuidNullUUIDToUuidNullUUID2(source.ParentStudioID) modelsStudio.CreatedAt = ConvertTime(source.CreatedAt) modelsStudio.UpdatedAt = ConvertTime(source.UpdatedAt) modelsStudio.Deleted = source.Deleted return modelsStudio } func (c *ModelConverterImpl) ConvertStudios(source []queries.Studio) []models.Studio { var modelsStudioList []models.Studio if source != nil { modelsStudioList = make([]models.Studio, len(source)) for i := 0; i < len(source); i++ { modelsStudioList[i] = c.ConvertStudio(source[i]) } } return modelsStudioList } func (c *ModelConverterImpl) ConvertTag(source queries.Tag) models.Tag { var modelsTag models.Tag modelsTag.ID = c.uuidUUIDToUuidUUID3(source.ID) modelsTag.Name = source.Name if source.Description != nil { xstring := *source.Description modelsTag.Description = &xstring } modelsTag.Deleted = source.Deleted modelsTag.CategoryID = c.uuidNullUUIDToUuidNullUUID2(source.CategoryID) modelsTag.Created = ConvertTime(source.CreatedAt) modelsTag.Updated = ConvertTime(source.UpdatedAt) return modelsTag } func (c *ModelConverterImpl) ConvertTagCategories(source []queries.TagCategory) []models.TagCategory { var modelsTagCategoryList []models.TagCategory if source != nil { modelsTagCategoryList = make([]models.TagCategory, len(source)) for i := 0; i < len(source); i++ { modelsTagCategoryList[i] = c.ConvertTagCategory(source[i]) } } return modelsTagCategoryList } func (c *ModelConverterImpl) ConvertTagCategory(source queries.TagCategory) models.TagCategory { var modelsTagCategory models.TagCategory modelsTagCategory.ID = c.uuidUUIDToUuidUUID3(source.ID) modelsTagCategory.Name = source.Name modelsTagCategory.Group = source.Group if source.Description != nil { xstring := *source.Description modelsTagCategory.Description = &xstring } modelsTagCategory.CreatedAt = ConvertTime(source.CreatedAt) modelsTagCategory.UpdatedAt = ConvertTime(source.UpdatedAt) return modelsTagCategory } func (c *ModelConverterImpl) ConvertTags(source []queries.Tag) []models.Tag { var modelsTagList []models.Tag if source != nil { modelsTagList = make([]models.Tag, len(source)) for i := 0; i < len(source); i++ { modelsTagList[i] = c.ConvertTag(source[i]) } } return modelsTagList } func (c *ModelConverterImpl) ConvertUser(source queries.User) models.User { var modelsUser models.User modelsUser.ID = c.uuidUUIDToUuidUUID3(source.ID) modelsUser.Name = source.Name modelsUser.PasswordHash = source.PasswordHash modelsUser.Email = source.Email modelsUser.APIKey = source.ApiKey modelsUser.APICalls = ConvertNullIntToInt(source.ApiCalls) modelsUser.InviteTokens = source.InviteTokens modelsUser.InvitedByID = c.uuidNullUUIDToUuidNullUUID2(source.InvitedBy) modelsUser.LastAPICall = ConvertTime(source.LastApiCall) modelsUser.CreatedAt = ConvertTime(source.CreatedAt) modelsUser.UpdatedAt = ConvertTime(source.UpdatedAt) return modelsUser } func (c *ModelConverterImpl) ConvertUserToken(source queries.UserToken) models.UserToken { var modelsUserToken models.UserToken modelsUserToken.ID = c.uuidUUIDToUuidUUID3(source.ID) modelsUserToken.Data = c.byteListToJsonRawMessage(source.Data) modelsUserToken.Type = source.Type modelsUserToken.CreatedAt = ConvertTime(source.CreatedAt) modelsUserToken.ExpiresAt = ConvertTime(source.ExpiresAt) return modelsUserToken } func (c *ModelConverterImpl) byteListToJsonRawMessage(source []uint8) json.RawMessage { var jsonRawMessage json.RawMessage if source != nil { jsonRawMessage = make(json.RawMessage, len(source)) for i := 0; i < len(source); i++ { jsonRawMessage[i] = source[i] } } return jsonRawMessage } func (c *ModelConverterImpl) modelsBreastTypeEnumToModelsBreastTypeEnum2(source models.BreastTypeEnum) models.BreastTypeEnum { var modelsBreastTypeEnum models.BreastTypeEnum switch source { case models.BreastTypeEnumFake: modelsBreastTypeEnum = models.BreastTypeEnumFake case models.BreastTypeEnumNa: modelsBreastTypeEnum = models.BreastTypeEnumNa case models.BreastTypeEnumNatural: modelsBreastTypeEnum = models.BreastTypeEnumNatural default: // ignored } return modelsBreastTypeEnum } func (c *ModelConverterImpl) modelsEthnicityEnumToModelsEthnicityEnum2(source models.EthnicityEnum) models.EthnicityEnum { var modelsEthnicityEnum models.EthnicityEnum switch source { case models.EthnicityEnumAsian: modelsEthnicityEnum = models.EthnicityEnumAsian case models.EthnicityEnumBlack: modelsEthnicityEnum = models.EthnicityEnumBlack case models.EthnicityEnumCaucasian: modelsEthnicityEnum = models.EthnicityEnumCaucasian case models.EthnicityEnumIndian: modelsEthnicityEnum = models.EthnicityEnumIndian case models.EthnicityEnumLatin: modelsEthnicityEnum = models.EthnicityEnumLatin case models.EthnicityEnumMiddleEastern: modelsEthnicityEnum = models.EthnicityEnumMiddleEastern case models.EthnicityEnumMixed: modelsEthnicityEnum = models.EthnicityEnumMixed case models.EthnicityEnumOther: modelsEthnicityEnum = models.EthnicityEnumOther default: // ignored } return modelsEthnicityEnum } func (c *ModelConverterImpl) modelsEyeColorEnumToModelsEyeColorEnum2(source models.EyeColorEnum) models.EyeColorEnum { var modelsEyeColorEnum models.EyeColorEnum switch source { case models.EyeColorEnumBlue: modelsEyeColorEnum = models.EyeColorEnumBlue case models.EyeColorEnumBrown: modelsEyeColorEnum = models.EyeColorEnumBrown case models.EyeColorEnumGreen: modelsEyeColorEnum = models.EyeColorEnumGreen case models.EyeColorEnumGrey: modelsEyeColorEnum = models.EyeColorEnumGrey case models.EyeColorEnumHazel: modelsEyeColorEnum = models.EyeColorEnumHazel case models.EyeColorEnumRed: modelsEyeColorEnum = models.EyeColorEnumRed default: // ignored } return modelsEyeColorEnum } func (c *ModelConverterImpl) modelsGenderEnumToModelsGenderEnum2(source models.GenderEnum) models.GenderEnum { var modelsGenderEnum models.GenderEnum switch source { case models.GenderEnumFemale: modelsGenderEnum = models.GenderEnumFemale case models.GenderEnumIntersex: modelsGenderEnum = models.GenderEnumIntersex case models.GenderEnumMale: modelsGenderEnum = models.GenderEnumMale case models.GenderEnumNonBinary: modelsGenderEnum = models.GenderEnumNonBinary case models.GenderEnumTransgenderFemale: modelsGenderEnum = models.GenderEnumTransgenderFemale case models.GenderEnumTransgenderMale: modelsGenderEnum = models.GenderEnumTransgenderMale default: // ignored } return modelsGenderEnum } func (c *ModelConverterImpl) modelsHairColorEnumToModelsHairColorEnum2(source models.HairColorEnum) models.HairColorEnum { var modelsHairColorEnum models.HairColorEnum switch source { case models.HairColorEnumAuburn: modelsHairColorEnum = models.HairColorEnumAuburn case models.HairColorEnumBald: modelsHairColorEnum = models.HairColorEnumBald case models.HairColorEnumBlack: modelsHairColorEnum = models.HairColorEnumBlack case models.HairColorEnumBlonde: modelsHairColorEnum = models.HairColorEnumBlonde case models.HairColorEnumBrunette: modelsHairColorEnum = models.HairColorEnumBrunette case models.HairColorEnumGrey: modelsHairColorEnum = models.HairColorEnumGrey case models.HairColorEnumOther: modelsHairColorEnum = models.HairColorEnumOther case models.HairColorEnumRed: modelsHairColorEnum = models.HairColorEnumRed case models.HairColorEnumVarious: modelsHairColorEnum = models.HairColorEnumVarious case models.HairColorEnumWhite: modelsHairColorEnum = models.HairColorEnumWhite default: // ignored } return modelsHairColorEnum } func (c *ModelConverterImpl) pTimeTimeToPTimeTime(source *time.Time) *time.Time { var pTimeTime *time.Time if source != nil { timeTime := ConvertTime((*source)) pTimeTime = &timeTime } return pTimeTime } func (c *ModelConverterImpl) uuidNullUUIDToUuidNullUUID2(source uuid.NullUUID) uuid.NullUUID { var uuidNullUUID uuid.NullUUID uuidNullUUID.UUID = c.uuidUUIDToUuidUUID3(source.UUID) uuidNullUUID.Valid = source.Valid return uuidNullUUID } func (c *ModelConverterImpl) uuidUUIDToUuidUUID3(source uuid.UUID) uuid.UUID { var uuidUUID uuid.UUID for i := 0; i < len(source); i++ { uuidUUID[i] = source[i] } return uuidUUID } type UpdateParamsConverterImpl struct{} func (c *UpdateParamsConverterImpl) ConvertEditToUpdateParams(source models.Edit) queries.UpdateEditParams { var queriesUpdateEditParams queries.UpdateEditParams queriesUpdateEditParams.ID = c.uuidUUIDToUuidUUID4(source.ID) queriesUpdateEditParams.Data = c.jsonRawMessageToByteList2(source.Data) queriesUpdateEditParams.Votes = source.VoteCount queriesUpdateEditParams.Status = source.Status queriesUpdateEditParams.Applied = source.Applied queriesUpdateEditParams.ClosedAt = c.pTimeTimeToPTimeTime2(source.ClosedAt) queriesUpdateEditParams.UpdateCount = source.UpdateCount return queriesUpdateEditParams } func (c *UpdateParamsConverterImpl) ConvertPerformerToUpdateParams(source models.Performer) queries.UpdatePerformerParams { var queriesUpdatePerformerParams queries.UpdatePerformerParams queriesUpdatePerformerParams.ID = c.uuidUUIDToUuidUUID4(source.ID) queriesUpdatePerformerParams.Name = source.Name if source.Disambiguation != nil { xstring := *source.Disambiguation queriesUpdatePerformerParams.Disambiguation = &xstring } if source.Gender != nil { modelsGenderEnum := c.modelsGenderEnumToModelsGenderEnum3(*source.Gender) queriesUpdatePerformerParams.Gender = &modelsGenderEnum } if source.BirthDate != nil { xstring2 := *source.BirthDate queriesUpdatePerformerParams.Birthdate = &xstring2 } if source.Ethnicity != nil { modelsEthnicityEnum := c.modelsEthnicityEnumToModelsEthnicityEnum3(*source.Ethnicity) queriesUpdatePerformerParams.Ethnicity = &modelsEthnicityEnum } if source.Country != nil { xstring3 := *source.Country queriesUpdatePerformerParams.Country = &xstring3 } if source.EyeColor != nil { modelsEyeColorEnum := c.modelsEyeColorEnumToModelsEyeColorEnum3(*source.EyeColor) queriesUpdatePerformerParams.EyeColor = &modelsEyeColorEnum } if source.HairColor != nil { modelsHairColorEnum := c.modelsHairColorEnumToModelsHairColorEnum3(*source.HairColor) queriesUpdatePerformerParams.HairColor = &modelsHairColorEnum } if source.Height != nil { xint := *source.Height queriesUpdatePerformerParams.Height = &xint } if source.CupSize != nil { xstring4 := *source.CupSize queriesUpdatePerformerParams.CupSize = &xstring4 } if source.BandSize != nil { xint2 := *source.BandSize queriesUpdatePerformerParams.BandSize = &xint2 } if source.HipSize != nil { xint3 := *source.HipSize queriesUpdatePerformerParams.HipSize = &xint3 } if source.WaistSize != nil { xint4 := *source.WaistSize queriesUpdatePerformerParams.WaistSize = &xint4 } if source.BreastType != nil { modelsBreastTypeEnum := c.modelsBreastTypeEnumToModelsBreastTypeEnum3(*source.BreastType) queriesUpdatePerformerParams.BreastType = &modelsBreastTypeEnum } if source.CareerStartYear != nil { xint5 := *source.CareerStartYear queriesUpdatePerformerParams.CareerStartYear = &xint5 } if source.CareerEndYear != nil { xint6 := *source.CareerEndYear queriesUpdatePerformerParams.CareerEndYear = &xint6 } if source.DeathDate != nil { xstring5 := *source.DeathDate queriesUpdatePerformerParams.Deathdate = &xstring5 } return queriesUpdatePerformerParams } func (c *UpdateParamsConverterImpl) ConvertSceneToUpdateParams(source models.Scene) queries.UpdateSceneParams { var queriesUpdateSceneParams queries.UpdateSceneParams queriesUpdateSceneParams.ID = c.uuidUUIDToUuidUUID4(source.ID) if source.Title != nil { xstring := *source.Title queriesUpdateSceneParams.Title = &xstring } if source.Details != nil { xstring2 := *source.Details queriesUpdateSceneParams.Details = &xstring2 } if source.Date != nil { xstring3 := *source.Date queriesUpdateSceneParams.Date = &xstring3 } if source.ProductionDate != nil { xstring4 := *source.ProductionDate queriesUpdateSceneParams.ProductionDate = &xstring4 } queriesUpdateSceneParams.StudioID = c.uuidNullUUIDToUuidNullUUID3(source.StudioID) if source.Duration != nil { xint := *source.Duration queriesUpdateSceneParams.Duration = &xint } if source.Director != nil { xstring5 := *source.Director queriesUpdateSceneParams.Director = &xstring5 } if source.Code != nil { xstring6 := *source.Code queriesUpdateSceneParams.Code = &xstring6 } return queriesUpdateSceneParams } func (c *UpdateParamsConverterImpl) ConvertSiteToUpdateParams(source models.Site) queries.UpdateSiteParams { var queriesUpdateSiteParams queries.UpdateSiteParams queriesUpdateSiteParams.ID = c.uuidUUIDToUuidUUID4(source.ID) queriesUpdateSiteParams.Name = source.Name if source.Description != nil { xstring := *source.Description queriesUpdateSiteParams.Description = &xstring } if source.URL != nil { xstring2 := *source.URL queriesUpdateSiteParams.Url = &xstring2 } if source.Regex != nil { xstring3 := *source.Regex queriesUpdateSiteParams.Regex = &xstring3 } if source.ValidTypes != nil { queriesUpdateSiteParams.ValidTypes = make([]string, len(source.ValidTypes)) for i := 0; i < len(source.ValidTypes); i++ { queriesUpdateSiteParams.ValidTypes[i] = source.ValidTypes[i] } } return queriesUpdateSiteParams } func (c *UpdateParamsConverterImpl) ConvertStudioToUpdateParams(source models.Studio) queries.UpdateStudioParams { var queriesUpdateStudioParams queries.UpdateStudioParams queriesUpdateStudioParams.ID = c.uuidUUIDToUuidUUID4(source.ID) queriesUpdateStudioParams.Name = source.Name queriesUpdateStudioParams.ParentStudioID = c.uuidNullUUIDToUuidNullUUID3(source.ParentStudioID) return queriesUpdateStudioParams } func (c *UpdateParamsConverterImpl) ConvertTagToUpdateParams(source models.Tag) queries.UpdateTagParams { var queriesUpdateTagParams queries.UpdateTagParams queriesUpdateTagParams.ID = c.uuidUUIDToUuidUUID4(source.ID) queriesUpdateTagParams.Name = source.Name queriesUpdateTagParams.CategoryID = c.uuidNullUUIDToUuidNullUUID3(source.CategoryID) if source.Description != nil { xstring := *source.Description queriesUpdateTagParams.Description = &xstring } return queriesUpdateTagParams } func (c *UpdateParamsConverterImpl) jsonRawMessageToByteList2(source json.RawMessage) []uint8 { var byteList []uint8 if source != nil { byteList = make([]uint8, len(source)) for i := 0; i < len(source); i++ { byteList[i] = source[i] } } return byteList } func (c *UpdateParamsConverterImpl) modelsBreastTypeEnumToModelsBreastTypeEnum3(source models.BreastTypeEnum) models.BreastTypeEnum { var modelsBreastTypeEnum models.BreastTypeEnum switch source { case models.BreastTypeEnumFake: modelsBreastTypeEnum = models.BreastTypeEnumFake case models.BreastTypeEnumNa: modelsBreastTypeEnum = models.BreastTypeEnumNa case models.BreastTypeEnumNatural: modelsBreastTypeEnum = models.BreastTypeEnumNatural default: // ignored } return modelsBreastTypeEnum } func (c *UpdateParamsConverterImpl) modelsEthnicityEnumToModelsEthnicityEnum3(source models.EthnicityEnum) models.EthnicityEnum { var modelsEthnicityEnum models.EthnicityEnum switch source { case models.EthnicityEnumAsian: modelsEthnicityEnum = models.EthnicityEnumAsian case models.EthnicityEnumBlack: modelsEthnicityEnum = models.EthnicityEnumBlack case models.EthnicityEnumCaucasian: modelsEthnicityEnum = models.EthnicityEnumCaucasian case models.EthnicityEnumIndian: modelsEthnicityEnum = models.EthnicityEnumIndian case models.EthnicityEnumLatin: modelsEthnicityEnum = models.EthnicityEnumLatin case models.EthnicityEnumMiddleEastern: modelsEthnicityEnum = models.EthnicityEnumMiddleEastern case models.EthnicityEnumMixed: modelsEthnicityEnum = models.EthnicityEnumMixed case models.EthnicityEnumOther: modelsEthnicityEnum = models.EthnicityEnumOther default: // ignored } return modelsEthnicityEnum } func (c *UpdateParamsConverterImpl) modelsEyeColorEnumToModelsEyeColorEnum3(source models.EyeColorEnum) models.EyeColorEnum { var modelsEyeColorEnum models.EyeColorEnum switch source { case models.EyeColorEnumBlue: modelsEyeColorEnum = models.EyeColorEnumBlue case models.EyeColorEnumBrown: modelsEyeColorEnum = models.EyeColorEnumBrown case models.EyeColorEnumGreen: modelsEyeColorEnum = models.EyeColorEnumGreen case models.EyeColorEnumGrey: modelsEyeColorEnum = models.EyeColorEnumGrey case models.EyeColorEnumHazel: modelsEyeColorEnum = models.EyeColorEnumHazel case models.EyeColorEnumRed: modelsEyeColorEnum = models.EyeColorEnumRed default: // ignored } return modelsEyeColorEnum } func (c *UpdateParamsConverterImpl) modelsGenderEnumToModelsGenderEnum3(source models.GenderEnum) models.GenderEnum { var modelsGenderEnum models.GenderEnum switch source { case models.GenderEnumFemale: modelsGenderEnum = models.GenderEnumFemale case models.GenderEnumIntersex: modelsGenderEnum = models.GenderEnumIntersex case models.GenderEnumMale: modelsGenderEnum = models.GenderEnumMale case models.GenderEnumNonBinary: modelsGenderEnum = models.GenderEnumNonBinary case models.GenderEnumTransgenderFemale: modelsGenderEnum = models.GenderEnumTransgenderFemale case models.GenderEnumTransgenderMale: modelsGenderEnum = models.GenderEnumTransgenderMale default: // ignored } return modelsGenderEnum } func (c *UpdateParamsConverterImpl) modelsHairColorEnumToModelsHairColorEnum3(source models.HairColorEnum) models.HairColorEnum { var modelsHairColorEnum models.HairColorEnum switch source { case models.HairColorEnumAuburn: modelsHairColorEnum = models.HairColorEnumAuburn case models.HairColorEnumBald: modelsHairColorEnum = models.HairColorEnumBald case models.HairColorEnumBlack: modelsHairColorEnum = models.HairColorEnumBlack case models.HairColorEnumBlonde: modelsHairColorEnum = models.HairColorEnumBlonde case models.HairColorEnumBrunette: modelsHairColorEnum = models.HairColorEnumBrunette case models.HairColorEnumGrey: modelsHairColorEnum = models.HairColorEnumGrey case models.HairColorEnumOther: modelsHairColorEnum = models.HairColorEnumOther case models.HairColorEnumRed: modelsHairColorEnum = models.HairColorEnumRed case models.HairColorEnumVarious: modelsHairColorEnum = models.HairColorEnumVarious case models.HairColorEnumWhite: modelsHairColorEnum = models.HairColorEnumWhite default: // ignored } return modelsHairColorEnum } func (c *UpdateParamsConverterImpl) pTimeTimeToPTimeTime2(source *time.Time) *time.Time { var pTimeTime *time.Time if source != nil { timeTime := ConvertTime((*source)) pTimeTime = &timeTime } return pTimeTime } func (c *UpdateParamsConverterImpl) uuidNullUUIDToUuidNullUUID3(source uuid.NullUUID) uuid.NullUUID { var uuidNullUUID uuid.NullUUID uuidNullUUID.UUID = c.uuidUUIDToUuidUUID4(source.UUID) uuidNullUUID.Valid = source.Valid return uuidNullUUID } func (c *UpdateParamsConverterImpl) uuidUUIDToUuidUUID4(source uuid.UUID) uuid.UUID { var uuidUUID uuid.UUID for i := 0; i < len(source); i++ { uuidUUID[i] = source[i] } return uuidUUID } ================================================ FILE: internal/converter/gen/interfaces.go ================================================ package gen //go:generate go run github.com/jmattheis/goverter/cmd/goverter gen . import ( "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/internal/queries" ) // ModelConverter handles all DB to Model conversions // goverter:converter // goverter:output:file ./generated.go // goverter:enum:unknown @ignore // goverter:extend ConvertNullIntToInt ConvertTime type ModelConverter interface { // goverter:map Url RemoteURL ConvertImage(source queries.Image) models.Image // goverter:map CreatedAt Created // goverter:map UpdatedAt Updated // goverter:map Birthdate BirthDate // goverter:map Deathdate DeathDate ConvertPerformer(source queries.Performer) models.Performer // goverter:map CreatedAt CreatedAt // goverter:map UpdatedAt UpdatedAt ConvertScene(source queries.Scene) models.Scene // goverter:map Url URL ConvertSite(source queries.Site) models.Site // goverter:map CreatedAt CreatedAt // goverter:map UpdatedAt UpdatedAt ConvertStudio(source queries.Studio) models.Studio // goverter:map CreatedAt CreatedAt // goverter:map UpdatedAt UpdatedAt ConvertTagCategory(source queries.TagCategory) models.TagCategory // goverter:map CreatedAt Created // goverter:map UpdatedAt Updated ConvertTag(source queries.Tag) models.Tag // goverter:map CreatedAt CreatedAt // goverter:map ExpiresAt ExpiresAt ConvertUserToken(source queries.UserToken) models.UserToken // goverter:map Votes VoteCount ConvertEdit(source queries.Edit) models.Edit ConvertEditVote(source queries.EditVote) models.EditVote ConvertEditComment(source queries.EditComment) models.EditComment // goverter:map ApiKey APIKey // goverter:map ApiCalls APICalls // goverter:map InvitedBy InvitedByID // goverter:map LastApiCall LastAPICall ConvertUser(source queries.User) models.User // goverter:map ExpireTime Expires ConvertInviteKey(source queries.InviteKey) models.InviteKey // goverter:map ID TargetID // goverter:map Type Type | ConvertNotificationType ConvertNotification(source queries.Notification) models.Notification // Slice converters ConvertImages(source []queries.Image) []models.Image ConvertEdits(source []queries.Edit) []models.Edit ConvertEditComments(source []queries.EditComment) []models.EditComment ConvertEditVotes(source []queries.EditVote) []models.EditVote ConvertPerformers(source []queries.Performer) []models.Performer ConvertScenes(source []queries.Scene) []models.Scene ConvertStudios(source []queries.Studio) []models.Studio ConvertTagCategories(source []queries.TagCategory) []models.TagCategory ConvertTags(source []queries.Tag) []models.Tag ConvertInviteKeys(source []queries.InviteKey) []models.InviteKey ConvertNotifications(source []queries.Notification) []models.Notification } // InputConverter handles all Input to Model conversions // goverter:converter // goverter:output:file ./generated.go // goverter:enum:unknown @ignore type InputConverter interface { // goverter:map Urls URLs // goverter:map Studio // goverter:ignore Tags // goverter:ignore Image ConvertSceneDraftInput(source models.SceneDraftInput) models.SceneDraft ConvertBodyModInputSlice(source []models.BodyModificationInput) []models.BodyModification } // CreateParamsConverter handles all Model to DB Create Params conversions // goverter:converter // goverter:output:file ./generated.go // goverter:enum:unknown @ignore // goverter:extend ConvertTime type CreateParamsConverter interface { ConvertTagToCreateParams(source models.Tag) queries.CreateTagParams ConvertStudioToCreateParams(source models.Studio) queries.CreateStudioParams ConvertSceneToCreateParams(source models.Scene) queries.CreateSceneParams // goverter:map BirthDate Birthdate // goverter:map DeathDate Deathdate ConvertPerformerToCreateParams(source models.Performer) queries.CreatePerformerParams // goverter:map UserID // goverter:map VoteCount Votes ConvertEditToCreateParams(source models.Edit) queries.CreateEditParams // goverter:map URL Url ConvertSiteToCreateParams(source models.Site) queries.CreateSiteParams ConvertEditCommentToCreateParams(source models.EditComment) queries.CreateEditCommentParams } // UpdateParamsConverter handles all Model to DB Update Params conversions // goverter:converter // goverter:output:file ./generated.go // goverter:enum:unknown @ignore // goverter:extend ConvertTime type UpdateParamsConverter interface { ConvertSceneToUpdateParams(source models.Scene) queries.UpdateSceneParams // goverter:map BirthDate Birthdate // goverter:map DeathDate Deathdate ConvertPerformerToUpdateParams(source models.Performer) queries.UpdatePerformerParams // goverter:map VoteCount Votes ConvertEditToUpdateParams(source models.Edit) queries.UpdateEditParams // goverter:map URL Url ConvertSiteToUpdateParams(source models.Site) queries.UpdateSiteParams ConvertTagToUpdateParams(source models.Tag) queries.UpdateTagParams ConvertStudioToUpdateParams(source models.Studio) queries.UpdateStudioParams } ================================================ FILE: internal/cron/cron.go ================================================ package cron import ( "context" "github.com/robfig/cron/v3" "golang.org/x/sync/semaphore" "github.com/stashapp/stash-box/internal/autocert" "github.com/stashapp/stash-box/internal/config" "github.com/stashapp/stash-box/internal/service" "github.com/stashapp/stash-box/pkg/logger" ) var sem = semaphore.NewWeighted(1) type Cron struct { fac service.Factory } // processEdits runs at set intervals and closes edits where the voting period has ended, // either by applying the edit if enough positive votes have been cast, or by rejecting it. func (c Cron) processEdits() { if !sem.TryAcquire(1) { logger.Debug("Edit cronjob failed to start, already running.") return } defer sem.Release(1) ctx := context.Background() closedEdits, err := c.fac.Edit().CloseCompleted(ctx) if err != nil { logger.Errorf("Error processing edits: %s", err) } // Trigger notifications for all closed edits for _, edit := range closedEdits { c.fac.Notification().OnApplyEdit(context.Background(), edit) } } func (c Cron) cleanDrafts() { ctx := context.Background() err := c.fac.Draft().DeleteExpired(ctx) if err != nil { logger.Errorf("Error cleaning drafts: %s", err) } } func (c Cron) cleanTokens() { ctx := context.Background() err := c.fac.UserToken().DestroyExpired(ctx) if err != nil { logger.Errorf("Error cleaning user tokens: %s", err) } } func (c Cron) cleanInvites() { ctx := context.Background() err := c.fac.Invite().DestroyExpired(ctx) if err != nil { logger.Errorf("Error cleaning invites: %s", err) } } func (c Cron) cleanNotifications() { ctx := context.Background() err := c.fac.Notification().DestroyExpired(ctx) if err != nil { logger.Errorf("Error cleaning notifications: %s", err) } } func (c Cron) cleanModAudits() { ctx := context.Background() retentionDays := config.GetModAuditRetentionDays() if retentionDays <= 0 { return } err := c.fac.ModAudit().DeleteExpired(ctx, retentionDays) if err != nil { logger.Errorf("Error cleaning mod audit logs: %s", err) } } func Init(fac service.Factory) { c := cron.New() cronJobs := Cron{fac} _, err := c.AddFunc("@every 5m", cronJobs.cleanDrafts) if err != nil { panic(err.Error()) } _, err = c.AddFunc("@every 1m", cronJobs.cleanTokens) if err != nil { panic(err.Error()) } _, err = c.AddFunc("@every 60m", cronJobs.cleanNotifications) if err != nil { panic(err.Error()) } _, err = c.AddFunc("@every 60m", cronJobs.cleanInvites) if err != nil { panic(err.Error()) } _, err = c.AddFunc("@every 12h", cronJobs.cleanModAudits) if err != nil { panic(err.Error()) } if config.GetAutocertConfig() != nil { _, err = c.AddFunc("@daily", autocert.CheckAndRenew) if err != nil { panic(err.Error()) } } interval := config.GetVoteCronInterval() if interval != "" { _, err := c.AddFunc("@every "+config.GetVoteCronInterval(), cronJobs.processEdits) if err != nil { panic(err.Error()) } c.Start() logger.Debugf("Edit cronjob initialized to run every %s", interval) } } ================================================ FILE: internal/database/database.go ================================================ package database import ( "context" "embed" "fmt" "strings" "time" "github.com/exaring/otelpgx" "github.com/golang-migrate/migrate/v4" "github.com/golang-migrate/migrate/v4/source/iofs" "github.com/jackc/pgx/v5/pgxpool" "github.com/stashapp/stash-box/internal/config" "github.com/stashapp/stash-box/pkg/logger" // Register pgx stdlib driver and postgres migrate driver _ "github.com/golang-migrate/migrate/v4/database/postgres" _ "github.com/jackc/pgx/v5/stdlib" ) const ( postgresDriver = "postgres" schemaVersion = 57 ) //go:embed migrations/postgres/*.sql var migrationsFS embed.FS // extractSQLCQueryName extracts the query name from sqlc-generated SQL comments // sqlc embeds query names as comments like: "-- name: GetUser :one" // For non-sqlc queries, returns the full query (otelpgx default behavior) func extractSQLCQueryName(query string) string { // Check if the query starts with a sqlc name comment if strings.HasPrefix(query, "-- name:") { parts := strings.Fields(query) if len(parts) > 2 { return parts[2] // Return the query name (e.g., "GetUser") } } return query // Fallback to full query for non-sqlc queries (default otelpgx behavior) } // Initialize opens a PostgreSQL connection pool and runs migrations func Initialize(databasePath string) *pgxpool.Pool { if err := runMigrations(databasePath); err != nil { logger.Fatal(err) } // Parse connection string into pgxpool config poolConfig, err := pgxpool.ParseConfig("postgres://" + databasePath) if err != nil { logger.Fatal(err) } // Set connection pool configuration poolConfig.MaxConns = int32(config.GetMaxOpenConns()) poolConfig.MinConns = int32(config.GetMaxIdleConns()) poolConfig.MaxConnLifetime = time.Duration(config.GetConnMaxLifetime()) * time.Minute // Add otelpgx tracing with custom span name function to use sqlc query names poolConfig.ConnConfig.Tracer = otelpgx.NewTracer( otelpgx.WithTrimSQLInSpanName(), otelpgx.WithSpanNameFunc(extractSQLCQueryName), ) // Create connection pool pool, err := pgxpool.NewWithConfig(context.Background(), poolConfig) if err != nil { logger.Fatal(err) } return pool } // runMigrations runs database migrations func runMigrations(databasePath string) error { migrations, err := iofs.New(migrationsFS, "migrations/postgres") if err != nil { return fmt.Errorf("failed to create migration source: %w", err) } m, err := migrate.NewWithSourceInstance( "iofs", migrations, fmt.Sprintf("%s://%s", postgresDriver, databasePath), ) if err != nil { return fmt.Errorf("failed to initialize migration: %w", err) } defer m.Close() m.Log = &migrateLogger{} databaseSchemaVersion, _, _ := m.Version() stepNumber := schemaVersion - databaseSchemaVersion if stepNumber != 0 { err = m.Steps(int(stepNumber)) if err != nil { return fmt.Errorf("failed to run database migrations: %w", err) } } return nil } type migrateLogger struct { migrate.Logger } // Printf is like fmt.Printf func (*migrateLogger) Printf(format string, v ...any) { logger.Debugf("Migration: "+format, v...) } // Verbose should return true when verbose logging output is wanted func (*migrateLogger) Verbose() bool { return true } ================================================ FILE: internal/database/migrations/postgres/01_initial.down.sql ================================================ DROP TABLE IF EXISTS "scene_fingerprints"; DROP TABLE IF EXISTS "scene_performers"; DROP TABLE IF EXISTS "scene_tags"; DROP TABLE IF EXISTS "studio_urls"; DROP TABLE IF EXISTS "tag_aliases"; DROP TABLE IF EXISTS "performer_aliases"; DROP TABLE IF EXISTS "performer_urls"; DROP TABLE IF EXISTS "performer_piercings"; DROP TABLE IF EXISTS "performer_tattoos"; DROP TABLE IF EXISTS "scenes"; DROP TABLE IF EXISTS "scene_urls"; DROP TABLE IF EXISTS "tags"; DROP TABLE IF EXISTS "performers"; DROP TABLE IF EXISTS "studios"; ================================================ FILE: internal/database/migrations/postgres/01_initial.up.sql ================================================ CREATE TABLE "performers" ( "id" uuid not null primary key, "name" varchar(255) not null, "disambiguation" varchar(255), "gender" varchar(20), "birthdate" date, "birthdate_accuracy" varchar(10), "ethnicity" varchar(20), "country" varchar(255), "eye_color" varchar(10), "hair_color" varchar(10), "height" integer, "cup_size" varchar(5), "band_size" integer, "hip_size" integer, "waist_size" integer, "breast_type" varchar(10), "career_start_year" integer, "career_end_year" integer, "created_at" timestamp not null, "updated_at" timestamp not null ); CREATE TABLE "performer_aliases" ( "performer_id" uuid not null, "alias" varchar(255) not null, foreign key("performer_id") references "performers"("id") ON DELETE CASCADE, unique ("performer_id", "alias") ); CREATE TABLE "performer_urls" ( "performer_id" uuid not null, "url" varchar not null, "type" varchar(255) not null, foreign key("performer_id") references "performers"("id") ON DELETE CASCADE, unique ("performer_id", "url"), unique ("performer_id", "type") ); CREATE TABLE "performer_piercings" ( "performer_id" uuid not null, "location" varchar(255), "description" varchar(255), foreign key("performer_id") references "performers"("id") ON DELETE CASCADE, unique ("performer_id", "location") ); CREATE TABLE "performer_tattoos" ( "performer_id" uuid not null, "location" varchar(255), "description" varchar(255), foreign key("performer_id") references "performers"("id") ON DELETE CASCADE, unique ("performer_id", "location") ); CREATE INDEX "index_performers_on_name" on "performers" ("name"); CREATE INDEX "index_performers_on_alias" on "performer_aliases" ("alias"); CREATE INDEX "index_performers_on_piercing_location" on "performer_piercings" ("location"); CREATE INDEX "index_performers_on_tattoo_location" on "performer_tattoos" ("location"); CREATE INDEX "index_performers_on_tattoo_description" on "performer_tattoos" ("description"); CREATE TABLE "tags" ( "id" uuid not null primary key, "name" varchar(255) not null, "description" varchar(255), "created_at" timestamp not null, "updated_at" timestamp not null, unique ("name") ); CREATE TABLE "tag_aliases" ( "tag_id" uuid not null, "alias" varchar(255) not null, foreign key("tag_id") references "tags"("id") ON DELETE CASCADE, unique ("alias") ); CREATE TABLE "studios" ( "id" uuid not null primary key, "name" varchar(255) not null, "parent_studio_id" uuid, "created_at" timestamp not null, "updated_at" timestamp not null, foreign key("parent_studio_id") references "studios"("id") ON DELETE CASCADE ); CREATE TABLE "studio_urls" ( "studio_id" uuid not null, "url" varchar not null, "type" varchar(255) not null, foreign key("studio_id") references "studios"("id") ON DELETE CASCADE, unique ("studio_id", "url"), unique ("studio_id", "type") ); CREATE TABLE "scenes" ( "id" uuid not null primary key, "title" varchar(255), "details" text, "date" date, "studio_id" uuid, "created_at" timestamp not null, "updated_at" timestamp not null, foreign key("studio_id") references "studios"("id") ON DELETE SET NULL ); CREATE TABLE "scene_urls" ( "scene_id" uuid not null, "url" varchar not null, "type" varchar(255) not null, foreign key("scene_id") references "scenes"("id") ON DELETE CASCADE, unique ("scene_id", "url"), unique ("scene_id", "type") ); CREATE TABLE "scene_fingerprints" ( "scene_id" uuid not null, "hash" varchar(255) not null, "algorithm" varchar(20) not null, foreign key("scene_id") references "scenes"("id") ON DELETE CASCADE, unique ("scene_id", "algorithm", "hash") ); CREATE INDEX "index_scene_fingerprints_on_hash" on "scene_fingerprints" ("algorithm", "hash"); CREATE TABLE "scene_performers" ( "scene_id" uuid not null, "as" varchar(255), "performer_id" uuid not null, foreign key("scene_id") references "scenes"("id") ON DELETE CASCADE, foreign key("performer_id") references "performers"("id") ON DELETE CASCADE, unique("scene_id", "performer_id") ); CREATE TABLE "scene_tags" ( "scene_id" uuid not null, "tag_id" uuid not null, foreign key("scene_id") references "scenes"("id") ON DELETE CASCADE, foreign key("tag_id") references "tags"("id") ON DELETE CASCADE, unique("scene_id", "tag_id") ); CREATE TABLE "users" ( "id" uuid not null primary key, "name" varchar(255) not null, "password_hash" varchar(60) not null, "email" varchar(255) not null, "api_key" varchar(255) not null, "api_calls" integer default 0, "last_api_call" timestamp not null, "created_at" timestamp not null, "updated_at" timestamp not null, unique ("name"), unique ("email") ); CREATE TABLE "user_roles" ( "user_id" uuid not null, "role" varchar(10) not null, foreign key("user_id") references "users"("id") ON DELETE CASCADE, unique ("user_id", "role") ); CREATE INDEX "index_users_on_name" on "users" ("name"); CREATE INDEX "index_users_on_email" on "users" ("email"); CREATE INDEX "index_users_on_api_key" on "users" ("api_key"); ================================================ FILE: internal/database/migrations/postgres/02_create_search.down.sql ================================================ DROP TABLE scene_search; DROP INDEX name_trgm_idx; DROP FUNCTION update_performers CASCADE; DROP FUNCTION update_scene CASCADE; DROP FUNCTION insert_scene CASCADE; DROP FUNCTION update_studio CASCADE; DROP FUNCTION update_scene_performers CASCADE; ================================================ FILE: internal/database/migrations/postgres/02_create_search.up.sql ================================================ DO $$ BEGIN IF current_setting('is_superuser') = 'on' THEN CREATE EXTENSION IF NOT EXISTS pg_trgm; END IF; END$$; CREATE TABLE scene_search AS SELECT S.id as scene_id, REGEXP_REPLACE(S.title, '[^a-zA-Z0-9 ]+', '', 'g') AS scene_title, S.date::TEXT AS scene_date, T.name || ' ' || REGEXP_REPLACE(T.name, '[^a-zA-Z0-9]', '', 'g') || ' ' || CASE WHEN TP.name IS NOT NULL THEN (TP.name || ' ' || REGEXP_REPLACE(TP.name, '[^a-zA-Z0-9]', '', 'g') ) ELSE '' END AS studio_name, STRING_AGG(P.name, ' ') || COALESCE(STRING_AGG(PS.as , ''), '') AS performer_names FROM scenes S LEFT JOIN scene_performers PS ON PS.scene_id = S.id LEFT JOIN performers P ON PS.performer_id = P.id LEFT JOIN studios T ON T.id = S.studio_id LEFT JOIN studios TP ON T.parent_studio_id = TP.id GROUP BY S.id, S.title, T.name, TP.name; CREATE INDEX name_trgm_idx ON performers USING GIN (name gin_trgm_ops); CREATE INDEX ts_idx ON scene_search USING gist ( ( to_tsvector('simple', COALESCE(scene_date, '')) || to_tsvector('english', studio_name) || to_tsvector('english', COALESCE(performer_names, '')) || to_tsvector('english', scene_title) ) ); CREATE OR REPLACE FUNCTION update_performers() RETURNS TRIGGER AS $$ BEGIN IF (NEW.name != OLD.name) THEN UPDATE scene_search SET performer_names = SUBQUERY.performer_names FROM ( SELECT S.id as scene_id, STRING_AGG(P.name, ' ') || COALESCE(STRING_AGG(PS.as , ''), '') AS performer_names FROM scenes S LEFT JOIN scene_performers PS ON PS.scene_id = S.id LEFT JOIN performers P ON PS.performer_id = P.id WHERE P.id = NEW.id GROUP BY S.id ) SUBQUERY WHERE scene_search.scene_id = SUBQUERY.scene_id; END IF; RETURN NULL; END; $$ LANGUAGE plpgsql; --The trigger used to update a table. DROP TRIGGER IF EXISTS update_performer_search_name ON performers; CREATE TRIGGER update_performer_search_name AFTER UPDATE ON performers FOR EACH ROW EXECUTE PROCEDURE update_performers(); CREATE OR REPLACE FUNCTION update_scene() RETURNS TRIGGER AS $$ BEGIN IF (NEW.title != OLD.title OR New.date != OLD.date) THEN UPDATE scene_search SET scene_title = REGEXP_REPLACE(NEW.title, '[^a-zA-Z0-9 ]+', '', 'g'), scene_date = NEW.date WHERE scene_id = NEW.id; END IF; RETURN NULL; END; $$ LANGUAGE plpgsql; --The trigger used to update a table. DROP TRIGGER IF EXISTS update_scene_search_title ON scenes; CREATE TRIGGER update_scene_search_title AFTER UPDATE ON scenes FOR EACH ROW EXECUTE PROCEDURE update_scene(); CREATE OR REPLACE FUNCTION insert_scene() RETURNS TRIGGER AS $$ BEGIN INSERT INTO scene_search (scene_id, scene_title, scene_date, studio_name) SELECT NEW.id, REGEXP_REPLACE(NEW.title, '[^a-zA-Z0-9 ]+', '', 'g'), NEW.date, T.name || ' ' || REGEXP_REPLACE(T.name, '[^a-zA-Z0-9]', '', 'g') || ' ' || CASE WHEN TP.name IS NOT NULL THEN (TP.name || ' ' || REGEXP_REPLACE(TP.name, '[^a-zA-Z0-9]', '', 'g') ) ELSE '' END FROM studios T LEFT JOIN studios TP ON T.parent_studio_id = TP.id WHERE T.id = NEW.studio_id; RETURN NULL; END; $$ LANGUAGE plpgsql; --The trigger used to update a table. DROP TRIGGER IF EXISTS insert_scene_search ON scenes; CREATE TRIGGER insert_scene_search AFTER INSERT ON scenes FOR EACH ROW EXECUTE PROCEDURE insert_scene(); CREATE OR REPLACE FUNCTION update_studio() RETURNS TRIGGER AS $$ BEGIN IF (NEW.name != OLD.name) THEN UPDATE scene_search SET studio_name = SUBQUERY.name FROM ( SELECT S.id, T.name || ' ' || REGEXP_REPLACE(T.name, '[^a-zA-Z0-9]', '', 'g') || ' ' || CASE WHEN TP.name IS NOT NULL THEN (TP.name || ' ' || REGEXP_REPLACE(TP.name, '[^a-zA-Z0-9]', '', 'g') ) ELSE '' END AS name FROM scenes S LEFT JOIN studios T ON T.id = S.studio_id LEFT JOIN studios TP ON T.parent_studio_id = TP.id WHERE T.id = NEW.id OR TP.id = NEW.id ) SUBQUERY WHERE scene_id = SUBQUERY.id; END IF; RETURN NULL; END; $$ LANGUAGE plpgsql; --The trigger used to update a table. DROP TRIGGER IF EXISTS update_studio_search_name ON studios; CREATE TRIGGER update_studio_search_name AFTER UPDATE ON studios FOR EACH ROW EXECUTE PROCEDURE update_studio(); CREATE OR REPLACE FUNCTION update_scene_performers() RETURNS TRIGGER AS $$ BEGIN UPDATE scene_search SET performer_names = SUBQUERY.performer_names FROM ( SELECT S.id as scene_id, STRING_AGG(P.name, ' ') || COALESCE(STRING_AGG(PS.as , ''), '') AS performer_names FROM scenes S LEFT JOIN scene_performers PS ON PS.scene_id = S.id LEFT JOIN performers P ON PS.performer_id = P.id WHERE S.id = OLD.scene_id GROUP BY S.id ) SUBQUERY WHERE scene_search.scene_id = SUBQUERY.scene_id; RETURN NULL; END; $$ LANGUAGE plpgsql; --The trigger used to update a table. DROP TRIGGER IF EXISTS update_scene_performers_search ON scene_performers; CREATE TRIGGER update_scene_performers_search AFTER INSERT OR UPDATE OR DELETE ON scene_performers FOR EACH ROW EXECUTE PROCEDURE update_scene_performers(); ================================================ FILE: internal/database/migrations/postgres/03_misc.up.sql ================================================ ALTER TABLE "scenes" ADD COLUMN duration integer, ADD COLUMN director TEXT; ALTER TABLE "scene_fingerprints" ADD COLUMN duration int; ================================================ FILE: internal/database/migrations/postgres/04_image_tables.up.sql ================================================ CREATE TABLE images ( id uuid PRIMARY KEY, url VARCHAR NOT NULL, width INT, height INT ); CREATE TABLE scene_images ( scene_id uuid REFERENCES scenes(id) NOT NULL, image_id uuid REFERENCES images(id) NOT NULL ); CREATE TABLE performer_images ( performer_id uuid REFERENCES performers(id) NOT NULL, image_id uuid REFERENCES images(id) NOT NULL ); CREATE TABLE studio_images ( studio_id uuid REFERENCES studios(id) NOT NULL, image_id uuid REFERENCES images(id) NOT NULL ); ================================================ FILE: internal/database/migrations/postgres/05_edits.up.sql ================================================ CREATE TABLE "edits" ( "id" uuid not null primary key, "user_id" uuid, "operation" varchar(10) not null, "target_type" varchar(10) not null, "data" jsonb, "votes" integer not null default 0, "status" varchar(20) not null, "applied" boolean default FALSE not null, "created_at" timestamp not null, "updated_at" timestamp not null, foreign key("user_id") references "users"("id") on delete set null ); CREATE INDEX edit_merge_sources_idx ON edits USING gin ((data->'merge_sources') jsonb_path_ops); CREATE TABLE "edit_comments" ( "id" UUID not null primary key, "edit_id" UUID not null, "user_id" UUID, "created_at" TIMESTAMP not null, "text" TEXT not null, FOREIGN KEY("edit_id") REFERENCES "edits"("id") ON DELETE CASCADE, FOREIGN KEY("user_id") REFERENCES "users"("id") ON DELETE SET NULL ); CREATE TABLE "performer_edits" ( "edit_id" uuid not null, "performer_id" uuid not null, foreign key("edit_id") references "edits"("id"), foreign key("performer_id") references "performers"("id") ); CREATE TABLE "studio_edits" ( "edit_id" uuid not null, "studio_id" uuid not null, foreign key("edit_id") references "edits"("id"), foreign key("studio_id") references "studios"("id") ); CREATE TABLE "tag_edits" ( "edit_id" uuid not null, "tag_id" uuid not null, foreign key("edit_id") references "edits"("id"), foreign key("tag_id") references "tags"("id") ); CREATE TABLE "scene_edits" ( "edit_id" uuid not null, "scene_id" uuid not null, foreign key("edit_id") references "edits"("id"), foreign key("scene_id") references "scenes"("id") ); ================================================ FILE: internal/database/migrations/postgres/06_deletion_and_redirects.up.sql ================================================ ALTER TABLE tags ADD COLUMN "deleted" BOOLEAN NOT NULL DEFAULT FALSE; ALTER TABLE performers ADD COLUMN "deleted" BOOLEAN NOT NULL DEFAULT FALSE; ALTER TABLE scenes ADD COLUMN "deleted" BOOLEAN NOT NULL DEFAULT FALSE; ALTER TABLE studios ADD COLUMN "deleted" BOOLEAN NOT NULL DEFAULT FALSE; ALTER TABLE tags DROP CONSTRAINT "tags_name_key"; CREATE UNIQUE INDEX "index_active_tags_on_name" on "tags" ("name") WHERE NOT "deleted"; DROP INDEX "index_performers_on_name"; CREATE UNIQUE INDEX "index_active_performers_on_name" on "performers" ("name", "disambiguation") WHERE NOT "deleted"; CREATE TABLE "tag_redirects" ( "source_id" UUID NOT NULL, "target_id" UUID NOT NULL, FOREIGN KEY("source_id") REFERENCES "tags"("id") ON DELETE CASCADE, FOREIGN KEY("target_id") REFERENCES "tags"("id") ON DELETE CASCADE, PRIMARY KEY ("source_id") ); CREATE TABLE "performer_redirects" ( "source_id" UUID NOT NULL, "target_id" UUID NOT NULL, FOREIGN KEY("source_id") REFERENCES "performers"("id") ON DELETE CASCADE, FOREIGN KEY("target_id") REFERENCES "performers"("id") ON DELETE CASCADE, PRIMARY KEY ("source_id") ); CREATE TABLE "scene_redirects" ( "source_id" UUID NOT NULL, "target_id" UUID NOT NULL, FOREIGN KEY("source_id") REFERENCES "scenes"("id") ON DELETE CASCADE, FOREIGN KEY("target_id") REFERENCES "scenes"("id") ON DELETE CASCADE, PRIMARY KEY ("source_id") ); CREATE TABLE "studio_redirects" ( "source_id" UUID NOT NULL, "target_id" UUID NOT NULL, FOREIGN KEY("source_id") REFERENCES "studios"("id") ON DELETE CASCADE, FOREIGN KEY("target_id") REFERENCES "studios"("id") ON DELETE CASCADE, PRIMARY KEY ("source_id") ); ================================================ FILE: internal/database/migrations/postgres/07_optimization_indexes.up.sql ================================================ CREATE INDEX performer_images_performer_id_idx ON performer_images (performer_id); CREATE INDEX scenes_date_idx ON scenes (date DESC NULLS LAST); CREATE INDEX scene_images_scene_id_idx ON scene_images (scene_id); CREATE INDEX scene_performers_performer_idx ON scene_performers (performer_id); CREATE INDEX scene_tags_tag_id_idx ON scene_tags (tag_id); CREATE INDEX scene_fingerprints_hash_idx ON scene_fingerprints (hash); CREATE INDEX studio_images_studio_id_idx ON studio_images (studio_id); CREATE INDEX tag_aliases_tag_id_idx ON tag_aliases (tag_id); CREATE INDEX tags_name_idx ON tags (name); ================================================ FILE: internal/database/migrations/postgres/08_user_invite.up.sql ================================================ ALTER TABLE "users" ADD COLUMN "invited_by" uuid, ADD COLUMN "invite_tokens" integer not null default 0, ADD foreign key("invited_by") references "users"("id") ON DELETE SET NULL; CREATE INDEX "user_invited_by_idx" ON "users" ("invited_by"); CREATE TABLE "invite_keys" ( "id" uuid not null primary key, "generated_by" uuid not null, "generated_at" timestamp not null, foreign key("generated_by") references "users"("id") on delete cascade ); CREATE INDEX "invite_keys_generated_by_idx" ON "invite_keys" ("generated_by"); CREATE TABLE "pending_activations" ( "id" uuid not null primary key, "email" varchar(255) not null, "invite_key" uuid, "type" varchar(255) not null, "time" timestamp not null, foreign key("invite_key") references "invite_keys"("id") ); CREATE UNIQUE INDEX "pending_activation_email_idx" on "pending_activations" ("email"); CREATE UNIQUE INDEX "pending_activation_invite_key_idx" on "pending_activations" ("invite_key"); ================================================ FILE: internal/database/migrations/postgres/09_image_data.up.sql ================================================ ALTER TABLE "images" ADD COLUMN "checksum" varchar(255) NOT NULL; ALTER TABLE "images" ALTER COLUMN "url" DROP NOT NULL; ALTER TABLE "images" ALTER COLUMN "width" SET NOT NULL; ALTER TABLE "images" ALTER COLUMN "height" SET NOT NULL; CREATE UNIQUE INDEX "images_checksum_idx" ON "images" ("checksum"); ================================================ FILE: internal/database/migrations/postgres/10_tag_categories.up.sql ================================================ CREATE TABLE tag_categories ( "id" uuid not null primary key, "group" text not null, "name" text not null, "description" text, "created_at" timestamp not null, "updated_at" timestamp not null, unique ("name") ); ALTER TABLE tags ADD COLUMN "category_id" uuid, ADD FOREIGN KEY ("category_id") REFERENCES "tag_categories"("id"); ================================================ FILE: internal/database/migrations/postgres/11_image_constraints.up.sql ================================================ ALTER TABLE "scene_images" DROP CONSTRAINT "scene_images_image_id_fkey", DROP CONSTRAINT "scene_images_scene_id_fkey", ADD CONSTRAINT "scene_images_image_id_fkey" FOREIGN KEY ("image_id") REFERENCES "images"("id") ON DELETE CASCADE, ADD CONSTRAINT "scene_images_scene_id_fkey" FOREIGN KEY ("scene_id") REFERENCES "scenes"("id") ON DELETE CASCADE; ALTER TABLE "performer_images" DROP CONSTRAINT "performer_images_image_id_fkey", DROP CONSTRAINT "performer_images_performer_id_fkey", ADD CONSTRAINT "performer_images_image_id_fkey" FOREIGN KEY ("image_id") REFERENCES "images"("id") ON DELETE CASCADE, ADD CONSTRAINT "performer_images_performer_id_fkey" FOREIGN KEY ("performer_id") REFERENCES "performers"("id") ON DELETE CASCADE; ALTER TABLE "studio_images" DROP CONSTRAINT "studio_images_image_id_fkey", DROP CONSTRAINT "studio_images_studio_id_fkey", ADD CONSTRAINT "studio_images_image_id_fkey" FOREIGN KEY ("image_id") REFERENCES "images"("id") ON DELETE CASCADE, ADD CONSTRAINT "studio_images_studio_id_fkey" FOREIGN KEY ("studio_id") REFERENCES "studios"("id") ON DELETE CASCADE; ================================================ FILE: internal/database/migrations/postgres/12_fix_performer_trigger.up.sql ================================================ TRUNCATE TABLE scene_search; INSERT INTO scene_search SELECT S.id as scene_id, REGEXP_REPLACE(S.title, '[^a-zA-Z0-9 ]+', '', 'g') AS scene_title, S.date::TEXT AS scene_date, T.name || ' ' || REGEXP_REPLACE(T.name, '[^a-zA-Z0-9]', '', 'g') || ' ' || CASE WHEN TP.name IS NOT NULL THEN (TP.name || ' ' || REGEXP_REPLACE(TP.name, '[^a-zA-Z0-9]', '', 'g') ) ELSE '' END AS studio_name, ARRAY_TO_STRING(ARRAY_CAT(ARRAY_AGG(P.name), ARRAY_AGG(PS.as)), ' ', '') AS performer_names FROM scenes S LEFT JOIN scene_performers PS ON PS.scene_id = S.id LEFT JOIN performers P ON PS.performer_id = P.id LEFT JOIN studios T ON T.id = S.studio_id LEFT JOIN studios TP ON T.parent_studio_id = TP.id GROUP BY S.id, S.title, T.name, TP.name; CREATE OR REPLACE FUNCTION update_performers() RETURNS TRIGGER AS $$ BEGIN IF (NEW.name != OLD.name) THEN UPDATE scene_search SET performer_names = SUBQUERY.performer_names FROM ( SELECT S.id as scene_id, ARRAY_TO_STRING(ARRAY_CAT(ARRAY_AGG(P.name), ARRAY_AGG(PPS.as)), ' ', '') AS performer_names FROM scene_performers PS JOIN scenes S ON PS.scene_id = S.id LEFT JOIN scene_performers PPS ON S.id = PPS.scene_id LEFT JOIN performers P ON PPS.performer_id = P.id WHERE PS.performer_id = NEW.id GROUP BY S.id ) SUBQUERY WHERE scene_search.scene_id = SUBQUERY.scene_id; END IF; RETURN NULL; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE FUNCTION update_scene_performers() RETURNS TRIGGER AS $$ BEGIN UPDATE scene_search SET performer_names = SUBQUERY.performer_names FROM ( SELECT PS.scene_id as scene_id, ARRAY_TO_STRING(ARRAY_CAT(ARRAY_AGG(P.name), ARRAY_AGG(PS.as)), ' ', '') AS performer_names FROM scene_performers PS LEFT JOIN performers P ON PS.performer_id = P.id WHERE PS.scene_id = NEW.scene_id GROUP BY PS.scene_id ) SUBQUERY WHERE scene_search.scene_id = COALESCE(NEW.scene_id, OLD.scene_id); RETURN NULL; END; $$ LANGUAGE plpgsql; ================================================ FILE: internal/database/migrations/postgres/13_sort_indexes.up.sql ================================================ CREATE INDEX "scene_search_scene_id_idx" ON "scene_search" ("scene_id"); ================================================ FILE: internal/database/migrations/postgres/14_phash_distance_search.up.sql ================================================ -- Enable bktree extension if available and user is superuser DO $$ DECLARE extension pg_available_extensions%rowtype; BEGIN SELECT * INTO extension FROM pg_available_extensions WHERE name='bktree'; IF found and current_setting('is_superuser') = 'on' THEN CREATE EXTENSION IF NOT EXISTS bktree; END IF; END$$; -- Create phash index if bktree is available DO $$ DECLARE extension pg_extension%rowtype; BEGIN SELECT * INTO extension FROM pg_extension WHERE extname='bktree'; IF found THEN CREATE INDEX scene_fingerprints_phash_index ON scene_fingerprints USING spgist ((('x' || hash)::bit(64)::bigint) bktree_ops) WHERE algorithm = 'PHASH'; END IF; END$$; ================================================ FILE: internal/database/migrations/postgres/15_scene_fingerprint_submissions.up.sql ================================================ -- Unused index DROP INDEX "index_scene_fingerprints_on_hash"; ALTER TABLE "scene_fingerprints" ADD CONSTRAINT "scene_hash_unique" UNIQUE ("scene_id", "hash"); ALTER TABLE "scene_fingerprints" DROP CONSTRAINT "scene_fingerprints_scene_id_algorithm_hash_key"; ALTER TABLE "scene_fingerprints" ADD COLUMN "submissions" INTEGER NOT NULL DEFAULT 1; ALTER TABLE "scene_fingerprints" ADD COLUMN "created_at" TIMESTAMP NOT NULL DEFAULT NOW(); ALTER TABLE "scene_fingerprints" ADD COLUMN "updated_at" TIMESTAMP NOT NULL DEFAULT NOW(); ================================================ FILE: internal/database/migrations/postgres/16_fix_scene_update_trigger.up.sql ================================================ TRUNCATE TABLE scene_search; INSERT INTO scene_search SELECT S.id as scene_id, REGEXP_REPLACE(S.title, '[^a-zA-Z0-9 ]+', '', 'g') AS scene_title, S.date::TEXT AS scene_date, T.name || ' ' || REGEXP_REPLACE(T.name, '[^a-zA-Z0-9]', '', 'g') || ' ' || CASE WHEN TP.name IS NOT NULL THEN (TP.name || ' ' || REGEXP_REPLACE(TP.name, '[^a-zA-Z0-9]', '', 'g') ) ELSE '' END AS studio_name, ARRAY_TO_STRING(ARRAY_CAT(ARRAY_AGG(P.name), ARRAY_AGG(PS.as)), ' ', '') AS performer_names FROM scenes S LEFT JOIN scene_performers PS ON PS.scene_id = S.id LEFT JOIN performers P ON PS.performer_id = P.id LEFT JOIN studios T ON T.id = S.studio_id LEFT JOIN studios TP ON T.parent_studio_id = TP.id GROUP BY S.id, S.title, T.name, TP.name; CREATE OR REPLACE FUNCTION update_scene() RETURNS TRIGGER AS $$ BEGIN IF (NEW.title != OLD.title OR New.date != OLD.date OR New.studio_id != OLD.studio_id) THEN UPDATE scene_search SET scene_title = REGEXP_REPLACE(NEW.title, '[^a-zA-Z0-9 ]+', '', 'g'), scene_date = NEW.date, studio_name = SUBQUERY.studio_name FROM ( SELECT S.id as sid, T.name || ' ' || REGEXP_REPLACE(T.name, '[^a-zA-Z0-9]', '', 'g') || ' ' || CASE WHEN TP.name IS NOT NULL THEN (TP.name || ' ' || REGEXP_REPLACE(TP.name, '[^a-zA-Z0-9]', '', 'g') ) ELSE '' END AS studio_name FROM scenes S JOIN studios T ON S.studio_id = T.id LEFT JOIN studios TP ON T.parent_studio_id = TP.id ) SUBQUERY WHERE scene_id = NEW.id AND scene_id = SUBQUERY.sid; END IF; RETURN NULL; END; $$ LANGUAGE plpgsql; --The trigger used to update a table. ================================================ FILE: internal/database/migrations/postgres/17_edit_votes.up.sql ================================================ UPDATE edits SET status = 'REJECTED', updated_at = NOW() WHERE status = 'PENDING'; UPDATE edits SET status = 'CANCELED' WHERE status = 'IMMEDIATE_REJECTED'; CREATE TABLE "edit_votes" ( "edit_id" UUID NOT NULL, "user_id" UUID NOT NULL, "created_at" TIMESTAMP NOT NULL, "vote" TEXT NOT NULL, PRIMARY KEY("edit_id", "user_id"), FOREIGN KEY("user_id") REFERENCES "users"("id"), FOREIGN KEY("edit_id") REFERENCES "edits"("id") ); CREATE OR REPLACE FUNCTION update_vote_count() RETURNS TRIGGER AS $$ BEGIN UPDATE edits SET votes = SUBQUERY.votesum FROM ( SELECT SUM( CASE WHEN vote = 'ACCEPT' THEN 1 WHEN vote = 'REJECT' THEN -1 ELSE 0 END ) as votesum FROM edit_votes WHERE edit_id = NEW.edit_id ) SUBQUERY WHERE id = NEW.edit_id; RETURN NULL; END; $$ LANGUAGE plpgsql; --The trigger used to update a table. DROP TRIGGER IF EXISTS update_edit_vote_count ON edit_votes; DROP TRIGGER IF EXISTS insert_edit_vote_count ON edit_votes; CREATE TRIGGER update_edit_vote_count AFTER UPDATE ON edit_votes FOR EACH ROW EXECUTE PROCEDURE update_vote_count(); CREATE TRIGGER insert_edit_vote_count AFTER INSERT ON edit_votes FOR EACH ROW EXECUTE PROCEDURE update_vote_count(); ================================================ FILE: internal/database/migrations/postgres/18_fingerprint_user.up.sql ================================================ DO $$ BEGIN IF current_setting('is_superuser') = 'on' THEN CREATE EXTENSION IF NOT EXISTS pgcrypto; END IF; END$$; ALTER TABLE "scene_fingerprints" ADD COLUMN user_id uuid references "users"("id") ON DELETE CASCADE; -- if there are existing fingerprints, create a user to assign them to it DO $$ BEGIN IF EXISTS (SELECT FROM "scene_fingerprints") THEN WITH "rows" AS ( INSERT INTO "users" ("id", "name", "password_hash", "email", "api_key", "last_api_call", "created_at", "updated_at") VALUES (gen_random_uuid(), '_legacy_submissions', '', 'N/A', '', LOCALTIMESTAMP, LOCALTIMESTAMP, LOCALTIMESTAMP) RETURNING "id" ) UPDATE "scene_fingerprints" SET "user_id" = (SELECT "id" FROM "rows"); END IF; END$$; ALTER TABLE "scene_fingerprints" ALTER COLUMN "user_id" SET NOT NULL; ALTER TABLE "scene_fingerprints" DROP CONSTRAINT "scene_hash_unique"; ALTER TABLE "scene_fingerprints" ADD CONSTRAINT "scene_hash_unique" UNIQUE ("scene_id", "algorithm", "hash", "user_id"); CREATE INDEX "index_scene_fingerprints_on_hash" on "scene_fingerprints" ("algorithm", "hash"); CREATE INDEX "index_scene_fingerprints_on_user" on "scene_fingerprints" ("user_id", "algorithm", "hash"); CREATE INDEX "index_scene_fingerprints_on_created_at" on "scene_fingerprints" ("created_at"); ================================================ FILE: internal/database/migrations/postgres/19_scene_created_index.up.sql ================================================ CREATE INDEX scenes_created_idx ON scenes(created_at DESC NULLS LAST); ================================================ FILE: internal/database/migrations/postgres/20_edit_constraints.up.sql ================================================ ALTER TABLE "performer_edits" DROP CONSTRAINT "performer_edits_edit_id_fkey", DROP CONSTRAINT "performer_edits_performer_id_fkey", ADD CONSTRAINT "performer_edits_edit_id_fkey" FOREIGN KEY ("edit_id") REFERENCES "edits"("id") ON DELETE CASCADE, ADD CONSTRAINT "performer_edits_performer_id_fkey" FOREIGN KEY ("performer_id") REFERENCES "performers"("id") ON DELETE CASCADE; ALTER TABLE "studio_edits" DROP CONSTRAINT "studio_edits_edit_id_fkey", DROP CONSTRAINT "studio_edits_studio_id_fkey", ADD CONSTRAINT "studio_edits_edit_id_fkey" FOREIGN KEY ("edit_id") REFERENCES "edits"("id") ON DELETE CASCADE, ADD CONSTRAINT "studio_edits_studio_id_fkey" FOREIGN KEY ("studio_id") REFERENCES "studios"("id") ON DELETE CASCADE; ALTER TABLE "tag_edits" DROP CONSTRAINT "tag_edits_edit_id_fkey", DROP CONSTRAINT "tag_edits_tag_id_fkey", ADD CONSTRAINT "tag_edits_edit_id_fkey" FOREIGN KEY ("edit_id") REFERENCES "edits"("id") ON DELETE CASCADE, ADD CONSTRAINT "tag_edits_tag_id_fkey" FOREIGN KEY ("tag_id") REFERENCES "tags"("id") ON DELETE CASCADE; ALTER TABLE "scene_edits" DROP CONSTRAINT "scene_edits_edit_id_fkey", DROP CONSTRAINT "scene_edits_scene_id_fkey", ADD CONSTRAINT "scene_edits_edit_id_fkey" FOREIGN KEY ("edit_id") REFERENCES "edits"("id") ON DELETE CASCADE, ADD CONSTRAINT "scene_edits_scene_id_fkey" FOREIGN KEY ("scene_id") REFERENCES "scenes"("id") ON DELETE CASCADE; ================================================ FILE: internal/database/migrations/postgres/21_site_urls.up.sql ================================================ CREATE TABLE "sites" ( "id" UUID NOT NULL PRIMARY KEY, "name" TEXT NOT NULL, "description" TEXT, "url" TEXT, "regex" TEXT, "valid_types" TEXT[] CHECK ("valid_types" <@ ARRAY['SCENE', 'PERFORMER', 'STUDIO']) NOT NULL, "created_at" TIMESTAMP NOT NULL, "updated_at" TIMESTAMP NOT NULL, UNIQUE ("name") ); INSERT INTO "sites" ( "id", "name", "valid_types", "created_at", "updated_at" ) VALUES ( '96d68ff6-cd18-4277-8633-5119abbdb635', 'Studio', ARRAY['SCENE'], NOW(), NOW() ); INSERT INTO "sites" ( "id", "name", "valid_types", "created_at", "updated_at" ) VALUES ( '1cda874a-bab4-44d8-b32b-c1e485e66b6f', 'Home', ARRAY['STUDIO'], NOW(), NOW() ); UPDATE "scene_urls" SET "type" = '96d68ff6-cd18-4277-8633-5119abbdb635' WHERE type = 'STUDIO'; UPDATE "studio_urls" SET "type" = '1cda874a-bab4-44d8-b32b-c1e485e66b6f' WHERE type = 'HOME'; ALTER TABLE "scene_urls" ALTER COLUMN "type" TYPE UUID USING type::uuid; ALTER TABLE "scene_urls" RENAME "type" TO "site_id"; ALTER TABLE "scene_urls" DROP CONSTRAINT IF EXISTS "scene_urls_scene_id_type_key"; ALTER TABLE "scene_urls" ADD CONSTRAINT "scene_urls_site_id_fkey" FOREIGN KEY ("site_id") REFERENCES "sites"("id"); ALTER TABLE "studio_urls" ALTER COLUMN "type" TYPE UUID USING type::uuid; ALTER TABLE "studio_urls" RENAME "type" TO "site_id"; ALTER TABLE "studio_urls" DROP CONSTRAINT IF EXISTS "studio_urls_studio_id_type_key"; ALTER TABLE "studio_urls" ADD CONSTRAINT "studio_urls_site_id_fkey" FOREIGN KEY ("site_id") REFERENCES "sites"("id"); ALTER TABLE "performer_urls" ALTER COLUMN "type" TYPE UUID USING type::uuid; ALTER TABLE "performer_urls" RENAME "type" TO "site_id"; ALTER TABLE "performer_urls" DROP CONSTRAINT IF EXISTS "performer_urls_performer_id_type_key"; ALTER TABLE "performer_urls" ADD CONSTRAINT "performer_urls_site_id_fkey" FOREIGN KEY ("site_id") REFERENCES "sites"("id"); ================================================ FILE: internal/database/migrations/postgres/22_performer_search_indexes.up.sql ================================================ CREATE INDEX disambiguation_trgm_idx ON "performers" USING GIN ("disambiguation" gin_trgm_ops); CREATE INDEX performer_alias_trgm_idx ON "performer_aliases" USING GIN ("alias" gin_trgm_ops); ================================================ FILE: internal/database/migrations/postgres/23_favorites.up.sql ================================================ CREATE TABLE performer_favorites ( performer_id uuid REFERENCES performers(id) ON DELETE CASCADE NOT NULL, user_id uuid REFERENCES users(id) ON DELETE CASCADE NOT NULL ); CREATE TABLE studio_favorites ( studio_id uuid REFERENCES studios(id) ON DELETE CASCADE NOT NULL, user_id uuid REFERENCES users(id) ON DELETE CASCADE NOT NULL ); CREATE INDEX scene_edit_performers_added_idx ON edits USING GIN (jsonb_path_query_array(data, '$.new_data.added_performers[*].performer_id')) WHERE target_type = 'SCENE'; CREATE INDEX scene_edit_performers_removed_idx ON edits USING GIN (jsonb_path_query_array(data, '$.new_data.removed_performers[*].performer_id')) WHERE target_type = 'SCENE'; ================================================ FILE: internal/database/migrations/postgres/24_drafts.up.sql ================================================ CREATE TABLE "drafts" ( "id" UUID PRIMARY KEY, "user_id" UUID NOT NULL, "type" TEXT CHECK ("type" in ('SCENE', 'PERFORMER', 'STUDIO')) NOT NULL, "data" JSONB NOT NULL, "created_at" TIMESTAMP NOT NULL, FOREIGN KEY("user_id") REFERENCES "users"("id") ON DELETE CASCADE ); ================================================ FILE: internal/database/migrations/postgres/25_scene_codes.up.sql ================================================ ALTER TABLE "scenes" ADD COLUMN code TEXT; ALTER TABLE "scene_search" ADD COLUMN scene_code TEXT; CREATE OR REPLACE FUNCTION update_scene() RETURNS TRIGGER AS $$ BEGIN IF (NEW.title != OLD.title OR NEW.date != OLD.date OR NEW.studio_id != OLD.studio_id OR COALESCE(NEW.code, '') != COALESCE(OLD.code, '')) THEN UPDATE scene_search SET scene_title = REGEXP_REPLACE(NEW.title, '[^a-zA-Z0-9 ]+', '', 'g'), scene_date = NEW.date, studio_name = SUBQUERY.studio_name, scene_code = NEW.code FROM ( SELECT S.id as sid, T.name || ' ' || REGEXP_REPLACE(T.name, '[^a-zA-Z0-9]', '', 'g') || ' ' || CASE WHEN TP.name IS NOT NULL THEN (TP.name || ' ' || REGEXP_REPLACE(TP.name, '[^a-zA-Z0-9]', '', 'g') ) ELSE '' END AS studio_name FROM scenes S JOIN studios T ON S.studio_id = T.id LEFT JOIN studios TP ON T.parent_studio_id = TP.id ) SUBQUERY WHERE scene_id = NEW.id AND scene_id = SUBQUERY.sid; END IF; RETURN NULL; END; $$ LANGUAGE plpgsql; --The trigger used to update a table. CREATE OR REPLACE FUNCTION insert_scene() RETURNS TRIGGER AS $$ BEGIN INSERT INTO scene_search (scene_id, scene_title, scene_date, studio_name, scene_code) SELECT NEW.id, REGEXP_REPLACE(NEW.title, '[^a-zA-Z0-9 ]+', '', 'g'), NEW.date, T.name || ' ' || REGEXP_REPLACE(T.name, '[^a-zA-Z0-9]', '', 'g') || ' ' || CASE WHEN TP.name IS NOT NULL THEN (TP.name || ' ' || REGEXP_REPLACE(TP.name, '[^a-zA-Z0-9]', '', 'g') ) ELSE '' END, NEW.code FROM studios T LEFT JOIN studios TP ON T.parent_studio_id = TP.id WHERE T.id = NEW.studio_id; RETURN NULL; END; $$ LANGUAGE plpgsql; --The trigger used to update a table. DROP INDEX ts_idx; CREATE INDEX scene_search_ts_idx ON scene_search USING gist ( ( to_tsvector('simple', COALESCE(scene_date, '')) || to_tsvector('english', studio_name) || to_tsvector('english', COALESCE(performer_names, '')) || to_tsvector('english', scene_title) || to_tsvector('simple', COALESCE(scene_code, '')) ) ); ================================================ FILE: internal/database/migrations/postgres/26_scene_partial_date.down.sql ================================================ ALTER TABLE "scenes" DROP COLUMN "date_accuracy"; ================================================ FILE: internal/database/migrations/postgres/26_scene_partial_date.up.sql ================================================ ALTER TABLE "scenes" ADD COLUMN "date_accuracy" varchar(10); UPDATE "scenes" SET "date_accuracy" = 'DAY'; ================================================ FILE: internal/database/migrations/postgres/27_edit_closed_at.up.sql ================================================ ALTER TABLE "edits" ADD COLUMN "closed_at" timestamp; ALTER TABLE "edits" ALTER COLUMN "updated_at" DROP NOT NULL; UPDATE "edits" SET "closed_at" = "updated_at" WHERE "updated_at" > "created_at" AND "status" != 'PENDING'; UPDATE "edits" SET "updated_at" = NULL; ================================================ FILE: internal/database/migrations/postgres/28_studio_favorite_index.up.sql ================================================ CREATE INDEX scene_edit_studio_added_idx ON edits ((data->'old_data'->>'studio_id')) WHERE target_type = 'SCENE'; CREATE INDEX scene_edit_studio_removed_idx ON edits ((data->'new_data'->>'studio_id')) WHERE target_type = 'SCENE'; ================================================ FILE: internal/database/migrations/postgres/29_scene_edit_fingerprint_index.up.sql ================================================ CREATE INDEX scene_edit_fingerprint_added_idx ON edits USING GIN (jsonb_path_query_array(data, '$.new_data.added_fingerprints[*].hash')) WHERE target_type = 'SCENE'; ================================================ FILE: internal/database/migrations/postgres/30_edit_bot.up.sql ================================================ ALTER TABLE "edits" ADD COLUMN "bot" BOOLEAN NOT NULL DEFAULT False; ================================================ FILE: internal/database/migrations/postgres/31_scenes_deleted_idx.up.sql ================================================ CREATE INDEX "scenes_deleted_idx" ON "scenes"("deleted"); CREATE INDEX "scenes_id_deleted_idx" ON "scenes"("id", "deleted"); CREATE INDEX "studio_favorites_idx" ON "studio_favorites"("studio_id", "user_id"); CREATE INDEX "performer_favorites_idx" ON "performer_favorites"("performer_id", "user_id"); ================================================ FILE: internal/database/migrations/postgres/32_edit_indexes.up.sql ================================================ CREATE INDEX "edit_votes_user_edit_idx" ON "edit_votes" ("user_id", "edit_id"); CREATE INDEX "edit_status_idx" ON edits ("status"); CREATE INDEX "edit_comments_edit_idx" ON "edit_comments" ("edit_id"); CREATE INDEX "scene_edits_scene_idx" ON "scene_edits" ("scene_id"); CREATE INDEX "scene_edits_edit_idx" ON "scene_edits" ("edit_id"); CREATE INDEX "performer_edits_edit_idx" ON "performer_edits" ("edit_id"); CREATE INDEX "tag_edits_edit_idx" ON "tag_edits" ("edit_id"); CREATE INDEX "studio_edits_edit_idx" ON "studio_edits" ("edit_id"); CREATE INDEX "studio_deleted_parent_idx" ON "studios" ("deleted", "parent_studio_id"); ================================================ FILE: internal/database/migrations/postgres/33_invite_key_uses.up.sql ================================================ ALTER TABLE "invite_keys" ADD COLUMN "uses" integer; ALTER TABLE "invite_keys" ADD COLUMN "expire_time" timestamp; ================================================ FILE: internal/database/migrations/postgres/34_fingerprints.up.sql ================================================ CREATE TABLE "fingerprints" ( "id" SERIAL PRIMARY KEY, "hash" VARCHAR(255) NOT NULL, "algorithm" VARCHAR(20) NOT NULL, UNIQUE ("hash", "algorithm") ); INSERT INTO "fingerprints" (hash, algorithm) SELECT hash, algorithm FROM "scene_fingerprints" GROUP BY hash, algorithm; ALTER TABLE "scene_fingerprints" RENAME TO "_scene_fingerprints"; CREATE TABLE "scene_fingerprints" ( "fingerprint_id" INT NOT NULL, "scene_id" UUID NOT NULL, "user_id" UUID NOT NULL, "duration" INT NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), FOREIGN KEY("fingerprint_id") REFERENCES "fingerprints"("id") ON DELETE CASCADE, FOREIGN KEY("scene_id") REFERENCES "scenes"("id") ON DELETE CASCADE, FOREIGN KEY("user_id") REFERENCES "users"("id") ON DELETE CASCADE, UNIQUE ("scene_id", "fingerprint_id", "user_id") ); INSERT INTO "scene_fingerprints" SELECT F.id, scene_id, user_id, duration, created_at FROM "_scene_fingerprints" SF JOIN "fingerprints" F ON SF.hash = F.hash AND SF.algorithm = F.algorithm; DROP TABLE "_scene_fingerprints"; CREATE INDEX "scene_fingerprints_fingerprint_idx" ON "scene_fingerprints" (fingerprint_id); CREATE INDEX "scene_fingerprints_user_idx" on "scene_fingerprints" (user_id); CREATE INDEX "scene_fingerprints_created_at" on "scene_fingerprints" (created_at, scene_id); -- Create phash index if bktree is available DO $$ DECLARE extension pg_extension%rowtype; BEGIN SELECT * INTO extension FROM pg_extension WHERE extname='bktree'; IF found THEN CREATE INDEX fingerprints_phash_idx ON fingerprints USING spgist ((('x' || hash)::bit(64)::bigint) bktree_ops) WHERE algorithm = 'PHASH'; END IF; END$$; ================================================ FILE: internal/database/migrations/postgres/35_websearch.up.sql ================================================ -- Update the index to match the format of querybuilder_scene.SearchScenes() DROP INDEX scene_search_ts_idx; CREATE INDEX scene_search_ts_idx ON scene_search USING gist ( ( to_tsvector('english', COALESCE(scene_date, '')) || to_tsvector('english', studio_name) || to_tsvector('english', COALESCE(performer_names, '')) || to_tsvector('english', scene_title) || to_tsvector('english', COALESCE(scene_code, '')) ) ); -- Update the scene_search functions to allow hyphens in the title when immediately followed by digit, to allow for JAV titles ex EMS-259 CREATE OR REPLACE FUNCTION update_scene() RETURNS TRIGGER AS $$ BEGIN IF (NEW.title != OLD.title OR NEW.date != OLD.date OR NEW.studio_id != OLD.studio_id OR COALESCE(NEW.code, '') != COALESCE(OLD.code, '')) THEN UPDATE scene_search SET scene_title = REGEXP_REPLACE(NEW.title, '[^a-zA-Z0-9 -:]+', '', 'g'), scene_date = NEW.date, studio_name = SUBQUERY.studio_name, scene_code = NEW.code FROM ( SELECT S.id as sid, T.name || ' ' || REGEXP_REPLACE(T.name, '[^a-zA-Z0-9]', '', 'g') || ' ' || CASE WHEN TP.name IS NOT NULL THEN (TP.name || ' ' || REGEXP_REPLACE(TP.name, '[^a-zA-Z0-9]', '', 'g') ) ELSE '' END AS studio_name FROM scenes S JOIN studios T ON S.studio_id = T.id LEFT JOIN studios TP ON T.parent_studio_id = TP.id ) SUBQUERY WHERE scene_id = NEW.id AND scene_id = SUBQUERY.sid; END IF; RETURN NULL; END; $$ LANGUAGE plpgsql; --The trigger used to update a table. CREATE OR REPLACE FUNCTION insert_scene() RETURNS TRIGGER AS $$ BEGIN INSERT INTO scene_search (scene_id, scene_title, scene_date, studio_name, scene_code) SELECT NEW.id, REGEXP_REPLACE(NEW.title, '[^a-zA-Z0-9 -:]+', '', 'g'), NEW.date, T.name || ' ' || REGEXP_REPLACE(T.name, '[^a-zA-Z0-9]', '', 'g') || ' ' || CASE WHEN TP.name IS NOT NULL THEN (TP.name || ' ' || REGEXP_REPLACE(TP.name, '[^a-zA-Z0-9]', '', 'g') ) ELSE '' END, NEW.code FROM studios T LEFT JOIN studios TP ON T.parent_studio_id = TP.id WHERE T.id = NEW.studio_id; RETURN NULL; END; $$ LANGUAGE plpgsql; --The trigger used to update a table. TRUNCATE TABLE scene_search; -- Recreate the table, allowing for JAV style titles like EMS-259 INSERT INTO scene_search SELECT S.id as scene_id, REGEXP_REPLACE(S.title, '[^a-zA-Z0-9 -:]+', '', 'g') AS scene_title, S.date::TEXT AS scene_date, T.name || ' ' || REGEXP_REPLACE(T.name, '[^a-zA-Z0-9]', '', 'g') || ' ' || CASE WHEN TP.name IS NOT NULL THEN (TP.name || ' ' || REGEXP_REPLACE(TP.name, '[^a-zA-Z0-9]', '', 'g') ) ELSE '' END AS studio_name, ARRAY_TO_STRING(ARRAY_CAT(ARRAY_AGG(P.name), ARRAY_AGG(PS.as)), ' ', '') AS performer_names, S.code as scene_code FROM scenes S LEFT JOIN scene_performers PS ON PS.scene_id = S.id LEFT JOIN performers P ON PS.performer_id = P.id LEFT JOIN studios T ON T.id = S.studio_id LEFT JOIN studios TP ON T.parent_studio_id = TP.id GROUP BY S.id, S.title, T.name, TP.name; ================================================ FILE: internal/database/migrations/postgres/36_drop_unique_invite.up.sql ================================================ DROP INDEX IF EXISTS "pending_activation_invite_key_idx"; ================================================ FILE: internal/database/migrations/postgres/37_tokens.up.sql ================================================ DROP TABLE "pending_activations"; CREATE TABLE "user_tokens" ( "id" UUID NOT NULL, "data" JSONB, "type" TEXT NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "expires_at" TIMESTAMP NOT NULL ); ================================================ FILE: internal/database/migrations/postgres/38_scenes_studio_id_index.up.sql ================================================ CREATE INDEX "scenes_studio_id_idx" ON "scenes" ("studio_id"); ================================================ FILE: internal/database/migrations/postgres/39_edits_updates.up.sql ================================================ ALTER TABLE "edits" ADD COLUMN "update_count" integer NOT NULL DEFAULT 0; UPDATE "edits" SET "update_count" = 1 WHERE "updated_at" IS NOT NULL; ================================================ FILE: internal/database/migrations/postgres/40_fingerprint_vote.up.sql ================================================ ALTER TABLE "scene_fingerprints" ADD COLUMN "vote" SMALLINT NOT NULL DEFAULT 1 CHECK (vote = -1 OR vote = 1); ================================================ FILE: internal/database/migrations/postgres/41_notifications.up.sql ================================================ DROP TYPE IF EXISTS notification_type; CREATE TYPE notification_type AS ENUM ( 'FAVORITE_PERFORMER_SCENE', 'FAVORITE_PERFORMER_EDIT', 'FAVORITE_STUDIO_SCENE', 'FAVORITE_STUDIO_EDIT', 'COMMENT_OWN_EDIT', 'DOWNVOTE_OWN_EDIT', 'FAILED_OWN_EDIT', 'COMMENT_COMMENTED_EDIT', 'COMMENT_VOTED_EDIT', 'UPDATED_EDIT' ); CREATE TABLE notifications ( user_id UUID REFERENCES users(id) ON DELETE CASCADE NOT NULL, type notification_type NOT NULL, id UUID NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT NOW(), read_at TIMESTAMP ); CREATE INDEX notifications_user_read_idx ON notifications (user_id, read_at); CREATE TABLE user_notifications ( user_id UUID REFERENCES users(id) ON DELETE CASCADE NOT NULL, type notification_type NOT NULL ); CREATE INDEX user_notifications_user_id_idx ON user_notifications (user_id); CREATE INDEX user_notifications_type_idx ON user_notifications (type); INSERT INTO user_notifications SELECT id, type FROM unnest(enum_range(NULL::notification_type)) AS type CROSS JOIN users; ================================================ FILE: internal/database/migrations/postgres/42_date_columns.up.sql ================================================ -- Transform scene date columns to single string column ALTER TABLE "scenes" RENAME COLUMN "date" TO "date_old"; ALTER TABLE "scenes" ADD COLUMN "date" TEXT; UPDATE "scenes" SET "date" = ( CASE WHEN "date_accuracy" = 'DAY' THEN TO_CHAR("date_old", 'YYYY-MM-DD') WHEN "date_accuracy" = 'MONTH' THEN TO_CHAR("date_old", 'YYYY-MM') WHEN "date_accuracy" = 'YEAR' THEN TO_CHAR("date_old", 'YYYY') END ); ALTER TABLE "scenes" DROP COLUMN "date_old"; ALTER TABLE "scenes" DROP COLUMN "date_accuracy"; -- Transform performers birthdate columns to single string column ALTER TABLE "performers" RENAME COLUMN "birthdate" TO "birthdate_old"; ALTER TABLE "performers" ADD COLUMN "birthdate" TEXT; UPDATE "performers" SET "birthdate" = ( CASE WHEN "birthdate_accuracy" = 'DAY' THEN TO_CHAR("birthdate_old", 'YYYY-MM-DD') WHEN "birthdate_accuracy" = 'MONTH' THEN TO_CHAR("birthdate_old", 'YYYY-MM') WHEN "birthdate_accuracy" = 'YEAR' THEN TO_CHAR("birthdate_old", 'YYYY') END ); ALTER TABLE "performers" DROP COLUMN "birthdate_old"; ALTER TABLE "performers" DROP COLUMN "birthdate_accuracy"; ================================================ FILE: internal/database/migrations/postgres/43_studio_aliases.up.sql ================================================ CREATE TABLE "studio_aliases" ( "studio_id" uuid not null, "alias" varchar(255) not null, foreign key("studio_id") references "studios"("id") ON DELETE CASCADE, unique ("alias") ); ================================================ FILE: internal/database/migrations/postgres/44_performer_death_date.up.sql ================================================ ALTER TABLE "performers" ADD COLUMN "deathdate" TEXT; ================================================ FILE: internal/database/migrations/postgres/45_scene_production_date.up.sql ================================================ ALTER TABLE "scenes" ADD COLUMN "production_date" TEXT; ================================================ FILE: internal/database/migrations/postgres/46_update_default_notifications.up.sql ================================================ DELETE FROM "user_notifications" WHERE type IN ( 'FAVORITE_PERFORMER_EDIT', 'FAVORITE_STUDIO_EDIT', 'FAVORITE_STUDIO_SCENE', 'FAVORITE_PERFORMER_SCENE' ); ================================================ FILE: internal/database/migrations/postgres/47_favorite_unique.up.sql ================================================ DELETE FROM "performer_favorites" PF WHERE EXISTS ( SELECT FROM "performer_favorites" WHERE performer_id = PF.performer_id AND user_id = PF.user_id AND ctid < PF.ctid ); CREATE UNIQUE INDEX "performer_favorites_unique_idx" ON "performer_favorites" (performer_id, user_id); DROP INDEX performer_favorites_idx; DELETE FROM "studio_favorites" SF WHERE EXISTS ( SELECT FROM "studio_favorites" WHERE studio_id = SF.studio_id AND user_id = SF.user_id AND ctid < SF.ctid ); CREATE UNIQUE INDEX "studio_favorites_unique_idx" ON "studio_favorites" (studio_id, user_id); DROP INDEX studio_favorites_idx; ALTER TABLE "performer_favorites" ADD COLUMN "created_at" TIMESTAMP; ALTER TABLE "performer_favorites" ALTER "created_at" SET DEFAULT NOW(); ALTER TABLE "studio_favorites" ADD COLUMN "created_at" TIMESTAMP; ALTER TABLE "studio_favorites" ALTER "created_at" SET DEFAULT NOW(); ================================================ FILE: internal/database/migrations/postgres/48_fingerprinted_scene_edit_notification.up.sql ================================================ ALTER TYPE notification_type ADD VALUE 'FINGERPRINTED_SCENE_EDIT'; ================================================ FILE: internal/database/migrations/postgres/49_entity_search_lower_idx.up.sql ================================================ CREATE INDEX performer_urls_url_lower_idx ON performer_urls (LOWER(url)); CREATE INDEX scene_urls_url_lower_idx ON scene_urls (LOWER(url)); ================================================ FILE: internal/database/migrations/postgres/50_rename_url_siteid.up.sql ================================================ -- Rename SiteID to site_id in URL objects within JSONB data -- Update added_urls in new_data UPDATE edits SET data = jsonb_set( data, '{new_data,added_urls}', ( SELECT COALESCE(jsonb_agg( CASE WHEN elem ? 'SiteID' THEN (elem - 'SiteID') || jsonb_build_object('site_id', elem->'SiteID') ELSE elem END ), '[]'::jsonb) FROM jsonb_array_elements(data->'new_data'->'added_urls') elem ) ) WHERE data->'new_data' ? 'added_urls' AND jsonb_typeof(data->'new_data'->'added_urls') = 'array'; -- Update removed_urls in new_data UPDATE edits SET data = jsonb_set( data, '{new_data,removed_urls}', ( SELECT COALESCE(jsonb_agg( CASE WHEN elem ? 'SiteID' THEN (elem - 'SiteID') || jsonb_build_object('site_id', elem->'SiteID') ELSE elem END ), '[]'::jsonb) FROM jsonb_array_elements(data->'new_data'->'removed_urls') elem ) ) WHERE data->'new_data' ? 'removed_urls' AND jsonb_typeof(data->'new_data'->'removed_urls') = 'array'; ================================================ FILE: internal/database/migrations/postgres/51_scene_deleted_sort_indexes.up.sql ================================================ DROP INDEX scenes_created_idx; DROP INDEX scenes_deleted_idx; DROP INDEX scenes_id_deleted_idx; CREATE INDEX scenes_deleted_created_at_id_idx ON scenes (created_at DESC, id DESC) WHERE deleted = false; CREATE INDEX scenes_deleted_updated_at_id_idx ON scenes (updated_at DESC, id DESC) WHERE deleted = false; CREATE INDEX scenes_deleted_date_id_idx ON scenes (date DESC, id DESC) WHERE deleted = false; CREATE INDEX scenes_deleted_title_id_idx ON scenes (title, id DESC) WHERE deleted = false; ================================================ FILE: internal/database/migrations/postgres/52_fingerprint_hash_bigint.up.sql ================================================ -- Remove MD5 hashes from fingerprints table DELETE FROM fingerprints WHERE algorithm = 'MD5'; -- Delete any hashes with non-hex values (must be valid 16-char hex for 64-bit conversion) DELETE FROM fingerprints WHERE hash !~ '^[0-9a-fA-F]{16}$'; -- Remove MD5 fingerprints from edit data (added_fingerprints) UPDATE edits SET data = jsonb_set( data, '{new_data,added_fingerprints}', ( SELECT COALESCE(jsonb_agg(fp), '[]'::jsonb) FROM jsonb_array_elements(data->'new_data'->'added_fingerprints') AS fp WHERE fp->>'algorithm' != 'MD5' ) ) WHERE data->'new_data'->'added_fingerprints' IS NOT NULL AND jsonb_array_length(data->'new_data'->'added_fingerprints') > 0; -- Remove MD5 fingerprints from drafts UPDATE drafts SET data = jsonb_set( data, '{fingerprints}', ( SELECT COALESCE(jsonb_agg(fp), '[]'::jsonb) FROM jsonb_array_elements(data->'fingerprints') AS fp WHERE fp->>'algorithm' != 'MD5' ) ) WHERE data->'fingerprints' IS NOT NULL AND jsonb_array_length(data->'fingerprints') > 0; ALTER TABLE fingerprints DROP CONSTRAINT fingerprints_hash_algorithm_key; DROP INDEX IF EXISTS fingerprints_phash_idx; ALTER TABLE fingerprints RENAME COLUMN hash TO hash_old; ALTER TABLE fingerprints ADD COLUMN hash BIGINT; UPDATE fingerprints SET hash = ('x' || hash_old)::bit(64)::bigint; ALTER TABLE fingerprints ALTER COLUMN hash SET NOT NULL; ALTER TABLE fingerprints DROP COLUMN hash_old; ALTER TABLE fingerprints ADD CONSTRAINT fingerprints_hash_algorithm_key UNIQUE (hash, algorithm); -- Recreate bktree index on new bigint hash column if extension is available DO $$ DECLARE extension pg_extension%rowtype; BEGIN SELECT * INTO extension FROM pg_extension WHERE extname='bktree'; IF found THEN CREATE INDEX fingerprints_phash_idx ON fingerprints USING spgist (hash bktree_ops) WHERE algorithm = 'PHASH'; END IF; END$$; ================================================ FILE: internal/database/migrations/postgres/53_varchar_to_text.up.sql ================================================ -- Body modifications ALTER TABLE performer_tattoos ALTER COLUMN location TYPE text; ALTER TABLE performer_tattoos ALTER COLUMN description TYPE text; ALTER TABLE performer_piercings ALTER COLUMN location TYPE text; ALTER TABLE performer_piercings ALTER COLUMN description TYPE text; -- Descriptions ALTER TABLE tags ALTER COLUMN description TYPE text; ALTER TABLE performers ALTER COLUMN disambiguation TYPE text; -- Aliases ALTER TABLE performer_aliases ALTER COLUMN alias TYPE text; ALTER TABLE studio_aliases ALTER COLUMN alias TYPE text; ALTER TABLE tag_aliases ALTER COLUMN alias TYPE text; -- Scene fields ALTER TABLE scenes ALTER COLUMN title TYPE text; ALTER TABLE scene_performers ALTER COLUMN "as" TYPE text; ================================================ FILE: internal/database/migrations/postgres/54_delete_soft_deleted_aliases.up.sql ================================================ DELETE FROM studio_aliases WHERE studio_id IN (SELECT id FROM studios WHERE deleted = true); DELETE FROM tag_aliases WHERE tag_id IN (SELECT id FROM tags WHERE deleted = true); ================================================ FILE: internal/database/migrations/postgres/55_fix_edit_data_dates.up.sql ================================================ -- Related to migration 42_date_columns.up.sql -- Transform scene date in edit data (date, date_accuracy) UPDATE edits SET data = data || CASE WHEN data->'old_data' ? 'date_accuracy' THEN -- build `{'old_data': <object>}` to replace the existing object jsonb_build_object( 'old_data', ( -- base object: the existing 'old_data', without `date_accuracy` (data->'old_data') - 'date_accuracy' ) || -- override object: `{'date': <new value>}` to replace the existing value in `new_data` jsonb_build_object( 'date', CASE data->'old_data'->>'date_accuracy' WHEN 'YEAR' THEN left(data->'old_data'->>'date', 4) WHEN 'MONTH' THEN left(data->'old_data'->>'date', 7) ELSE data->'old_data'->>'date' END ) ) -- if `date_accuracy` does not exist, override nothing and continue ELSE '{}'::jsonb END || CASE WHEN data->'new_data' ? 'date_accuracy' THEN -- build `{'new_data': <object>}` to replace the existing object jsonb_build_object( 'new_data', ( -- base object: the existing 'new_data', without `date_accuracy` (data->'new_data') - 'date_accuracy' ) || -- override object: `{'date': <new value>}` to replace the existing value in `new_data` jsonb_build_object( 'date', CASE data->'new_data'->>'date_accuracy' WHEN 'YEAR' THEN left(data->'new_data'->>'date', 4) WHEN 'MONTH' THEN left(data->'new_data'->>'date', 7) ELSE data->'new_data'->>'date' END ) ) -- if `date_accuracy` does not exist, override nothing and continue ELSE '{}'::jsonb END WHERE (data->'old_data' ? 'date_accuracy') OR (data->'new_data' ? 'date_accuracy'); -- Transform performers birthdate in edit data (birthdate, birthdate_accuracy) UPDATE edits SET data = data || CASE WHEN data->'old_data' ? 'birthdate_accuracy' THEN -- build `{'old_data': <object>}` to replace the existing object jsonb_build_object( 'old_data', ( -- base object: the existing 'old_data', without `birthdate_accuracy` (data->'old_data') - 'birthdate_accuracy' ) || -- override object: `{'birthdate': <new value>}` to replace the existing value in `new_data` jsonb_build_object( 'birthdate', CASE data->'old_data'->>'birthdate_accuracy' WHEN 'YEAR' THEN left(data->'old_data'->>'birthdate', 4) WHEN 'MONTH' THEN left(data->'old_data'->>'birthdate', 7) ELSE data->'old_data'->>'birthdate' END ) ) -- if `birthdate_accuracy` does not exist, override nothing and continue ELSE '{}'::jsonb END || CASE WHEN data->'new_data' ? 'birthdate_accuracy' THEN -- build `{'new_data': <object>}` to replace the existing object jsonb_build_object( 'new_data', ( -- base object: the existing 'new_data', without `birthdate_accuracy` (data->'new_data') - 'birthdate_accuracy' ) || -- build `{'birthdate': <new value>}` to replace the existing value in `new_data` jsonb_build_object( 'birthdate', CASE data->'new_data'->>'birthdate_accuracy' WHEN 'YEAR' THEN left(data->'new_data'->>'birthdate', 4) WHEN 'MONTH' THEN left(data->'new_data'->>'birthdate', 7) ELSE data->'new_data'->>'birthdate' END ) ) -- if `birthdate_accuracy` does not exist, override nothing and continue ELSE '{}'::jsonb END WHERE (data->'old_data' ? 'birthdate_accuracy') OR (data->'new_data' ? 'birthdate_accuracy'); ================================================ FILE: internal/database/migrations/postgres/56_paradedb_search.up.sql ================================================ CREATE EXTENSION IF NOT EXISTS pg_search; -- =========================================== -- Remove old scene_search infrastructure -- =========================================== DROP TRIGGER IF EXISTS update_performer_search_name ON performers; DROP TRIGGER IF EXISTS update_scene_search_title ON scenes; DROP TRIGGER IF EXISTS insert_scene_search ON scenes; DROP TRIGGER IF EXISTS update_studio_search_name ON studios; DROP TRIGGER IF EXISTS update_scene_performers_search ON scene_performers; DROP FUNCTION IF EXISTS update_performers(); DROP FUNCTION IF EXISTS update_scene(); DROP FUNCTION IF EXISTS insert_scene(); DROP FUNCTION IF EXISTS update_studio(); DROP FUNCTION IF EXISTS update_scene_performers(); DROP INDEX IF EXISTS scene_search_ts_idx; DROP INDEX IF EXISTS scene_search_scene_id_idx; DROP TABLE IF EXISTS scene_search; -- =========================================== -- Scene search -- =========================================== CREATE TABLE scene_search ( scene_id UUID PRIMARY KEY REFERENCES scenes(id) ON DELETE CASCADE, scene_title TEXT, scene_date TEXT, studio_name TEXT, network_name TEXT, performer_names TEXT[], scene_code TEXT ); INSERT INTO scene_search SELECT S.id, S.title, S.date::TEXT, T.name, TP.name, COALESCE(ARRAY_AGG(DISTINCT P.name) FILTER (WHERE P.name IS NOT NULL), '{}') || COALESCE(ARRAY_AGG(DISTINCT PS."as") FILTER (WHERE PS."as" IS NOT NULL), '{}'), S.code FROM scenes S LEFT JOIN scene_performers PS ON PS.scene_id = S.id LEFT JOIN performers P ON PS.performer_id = P.id LEFT JOIN studios T ON T.id = S.studio_id LEFT JOIN studios TP ON T.parent_studio_id = TP.id WHERE S.deleted = false GROUP BY S.id, T.name, TP.name; CREATE INDEX scene_search_bm25_idx ON scene_search USING bm25 ( scene_id, scene_title, scene_date, studio_name, network_name, performer_names, scene_code ) WITH (key_field='scene_id'); CREATE OR REPLACE FUNCTION upsert_scene_search(sid UUID) RETURNS VOID AS $$ BEGIN -- Remove from search if soft-deleted DELETE FROM scene_search WHERE scene_id = sid AND EXISTS (SELECT 1 FROM scenes WHERE id = sid AND deleted = true); -- Insert/update only if not deleted INSERT INTO scene_search (scene_id, scene_title, scene_date, studio_name, network_name, performer_names, scene_code) SELECT S.id, S.title, S.date::TEXT, T.name, TP.name, COALESCE(ARRAY_AGG(DISTINCT P.name) FILTER (WHERE P.name IS NOT NULL), '{}') || COALESCE(ARRAY_AGG(DISTINCT PS."as") FILTER (WHERE PS."as" IS NOT NULL), '{}'), S.code FROM scenes S LEFT JOIN scene_performers PS ON PS.scene_id = S.id LEFT JOIN performers P ON PS.performer_id = P.id LEFT JOIN studios T ON T.id = S.studio_id LEFT JOIN studios TP ON T.parent_studio_id = TP.id WHERE S.id = sid AND S.deleted = false GROUP BY S.id, T.name, TP.name ON CONFLICT (scene_id) DO UPDATE SET scene_title = EXCLUDED.scene_title, scene_date = EXCLUDED.scene_date, studio_name = EXCLUDED.studio_name, network_name = EXCLUDED.network_name, performer_names = EXCLUDED.performer_names, scene_code = EXCLUDED.scene_code; END; $$ LANGUAGE plpgsql; -- On scene insert/update CREATE OR REPLACE FUNCTION trg_scene_changed() RETURNS TRIGGER AS $$ BEGIN PERFORM upsert_scene_search(NEW.id); RETURN NULL; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trg_scene_search_on_scene AFTER INSERT OR UPDATE ON scenes FOR EACH ROW EXECUTE FUNCTION trg_scene_changed(); -- On performer name change -> repopulate all their scenes CREATE OR REPLACE FUNCTION trg_performer_changed_scenes() RETURNS TRIGGER AS $$ BEGIN PERFORM upsert_scene_search(scene_id) FROM scene_performers WHERE performer_id = NEW.id; RETURN NULL; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trg_scene_search_on_performer AFTER UPDATE ON performers FOR EACH ROW EXECUTE FUNCTION trg_performer_changed_scenes(); -- Studio name change -> populate scenes under this studio and its child studios CREATE OR REPLACE FUNCTION trg_studio_changed_scenes() RETURNS TRIGGER AS $$ BEGIN -- Scenes directly under this studio PERFORM upsert_scene_search(id) FROM scenes WHERE studio_id = NEW.id; -- Scenes under child studios (network name changed) PERFORM upsert_scene_search(S.id) FROM scenes S JOIN studios ST ON S.studio_id = ST.id WHERE ST.parent_studio_id = NEW.id; RETURN NULL; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trg_scene_search_on_studio AFTER UPDATE ON studios FOR EACH ROW EXECUTE FUNCTION trg_studio_changed_scenes(); -- On scene_performers insert CREATE OR REPLACE FUNCTION trg_scene_performers_inserted() RETURNS TRIGGER AS $$ BEGIN PERFORM upsert_scene_search(scene_id) FROM (SELECT DISTINCT scene_id FROM new_rows) affected; RETURN NULL; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trg_scene_search_on_sp_insert AFTER INSERT ON scene_performers REFERENCING NEW TABLE AS new_rows FOR EACH STATEMENT EXECUTE FUNCTION trg_scene_performers_inserted(); -- On scene_performers delete CREATE OR REPLACE FUNCTION trg_scene_performers_deleted() RETURNS TRIGGER AS $$ BEGIN PERFORM upsert_scene_search(scene_id) FROM (SELECT DISTINCT scene_id FROM old_rows) affected; RETURN NULL; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trg_scene_search_on_sp_delete AFTER DELETE ON scene_performers REFERENCING OLD TABLE AS old_rows FOR EACH STATEMENT EXECUTE FUNCTION trg_scene_performers_deleted(); -- =========================================== -- Performer search -- =========================================== CREATE TABLE performer_search ( performer_id UUID PRIMARY KEY REFERENCES performers(id) ON DELETE CASCADE, name TEXT, disambiguation TEXT, aliases TEXT[], gender TEXT ); INSERT INTO performer_search SELECT P.id, P.name, P.disambiguation, ARRAY_AGG(PA.alias) FILTER (WHERE PA.alias IS NOT NULL), P.gender FROM performers P LEFT JOIN performer_aliases PA ON PA.performer_id = P.id WHERE P.deleted = false GROUP BY P.id; CREATE INDEX performer_search_bm25_idx ON performer_search USING bm25 ( performer_id, name, disambiguation, aliases, (gender::pdb.literal) ) WITH (key_field='performer_id'); CREATE OR REPLACE FUNCTION upsert_performer_search(pid UUID) RETURNS VOID AS $$ BEGIN -- Remove from search if soft-deleted DELETE FROM performer_search WHERE performer_id = pid AND EXISTS (SELECT 1 FROM performers WHERE id = pid AND deleted = true); -- Insert/update only if not deleted INSERT INTO performer_search (performer_id, name, disambiguation, aliases, gender) SELECT P.id, P.name, P.disambiguation, ARRAY_AGG(PA.alias) FILTER (WHERE PA.alias IS NOT NULL), P.gender FROM performers P LEFT JOIN performer_aliases PA ON PA.performer_id = P.id WHERE P.id = pid AND P.deleted = false GROUP BY P.id ON CONFLICT (performer_id) DO UPDATE SET name = EXCLUDED.name, disambiguation = EXCLUDED.disambiguation, aliases = EXCLUDED.aliases, gender = EXCLUDED.gender; END; $$ LANGUAGE plpgsql; -- On performer insert/update CREATE OR REPLACE FUNCTION trg_performer_changed() RETURNS TRIGGER AS $$ BEGIN PERFORM upsert_performer_search(NEW.id); RETURN NULL; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trg_performer_search_on_performer AFTER INSERT OR UPDATE ON performers FOR EACH ROW EXECUTE FUNCTION trg_performer_changed(); -- On performer_aliases insert CREATE OR REPLACE FUNCTION trg_performer_aliases_inserted() RETURNS TRIGGER AS $$ BEGIN PERFORM upsert_performer_search(performer_id) FROM (SELECT DISTINCT performer_id FROM new_rows) affected; RETURN NULL; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trg_performer_search_on_alias_insert AFTER INSERT ON performer_aliases REFERENCING NEW TABLE AS new_rows FOR EACH STATEMENT EXECUTE FUNCTION trg_performer_aliases_inserted(); -- On performer_aliases delete CREATE OR REPLACE FUNCTION trg_performer_aliases_deleted() RETURNS TRIGGER AS $$ BEGIN PERFORM upsert_performer_search(performer_id) FROM (SELECT DISTINCT performer_id FROM old_rows) affected; RETURN NULL; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trg_performer_search_on_alias_delete AFTER DELETE ON performer_aliases REFERENCING OLD TABLE AS old_rows FOR EACH STATEMENT EXECUTE FUNCTION trg_performer_aliases_deleted(); -- =========================================== -- Studio search -- =========================================== CREATE TABLE studio_search ( studio_id UUID PRIMARY KEY REFERENCES studios(id) ON DELETE CASCADE, name TEXT, network TEXT, aliases TEXT[] ); INSERT INTO studio_search SELECT S.id, S.name, SP.name, ARRAY_AGG(SA.alias) FILTER (WHERE SA.alias IS NOT NULL) FROM studios S LEFT JOIN studios SP ON S.parent_studio_id = SP.id LEFT JOIN studio_aliases SA ON SA.studio_id = S.id WHERE S.deleted = false GROUP BY S.id, SP.name; CREATE INDEX studio_search_bm25_idx ON studio_search USING bm25 (studio_id, name, network, aliases) WITH (key_field='studio_id'); CREATE OR REPLACE FUNCTION upsert_studio_search(sid UUID) RETURNS VOID AS $$ BEGIN -- Remove from search if soft-deleted DELETE FROM studio_search WHERE studio_id = sid AND EXISTS (SELECT 1 FROM studios WHERE id = sid AND deleted = true); -- Insert/update only if not deleted INSERT INTO studio_search (studio_id, name, network, aliases) SELECT S.id, S.name, SP.name, ARRAY_AGG(SA.alias) FILTER (WHERE SA.alias IS NOT NULL) FROM studios S LEFT JOIN studios SP ON S.parent_studio_id = SP.id LEFT JOIN studio_aliases SA ON SA.studio_id = S.id WHERE S.id = sid AND S.deleted = false GROUP BY S.id, SP.name ON CONFLICT (studio_id) DO UPDATE SET name = EXCLUDED.name, network = EXCLUDED.network, aliases = EXCLUDED.aliases; END; $$ LANGUAGE plpgsql; -- On studio insert/update -> upsert self + upsert child studios (parent name changed) CREATE OR REPLACE FUNCTION trg_studio_changed() RETURNS TRIGGER AS $$ BEGIN PERFORM upsert_studio_search(NEW.id); -- If name changed, update child studios that reference this as parent PERFORM upsert_studio_search(id) FROM studios WHERE parent_studio_id = NEW.id; RETURN NULL; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trg_studio_search_on_studio AFTER INSERT OR UPDATE ON studios FOR EACH ROW EXECUTE FUNCTION trg_studio_changed(); -- On studio_aliases insert CREATE OR REPLACE FUNCTION trg_studio_aliases_inserted() RETURNS TRIGGER AS $$ BEGIN PERFORM upsert_studio_search(studio_id) FROM (SELECT DISTINCT studio_id FROM new_rows) affected; RETURN NULL; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trg_studio_search_on_alias_insert AFTER INSERT ON studio_aliases REFERENCING NEW TABLE AS new_rows FOR EACH STATEMENT EXECUTE FUNCTION trg_studio_aliases_inserted(); -- On studio_aliases delete CREATE OR REPLACE FUNCTION trg_studio_aliases_deleted() RETURNS TRIGGER AS $$ BEGIN PERFORM upsert_studio_search(studio_id) FROM (SELECT DISTINCT studio_id FROM old_rows) affected; RETURN NULL; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trg_studio_search_on_alias_delete AFTER DELETE ON studio_aliases REFERENCING OLD TABLE AS old_rows FOR EACH STATEMENT EXECUTE FUNCTION trg_studio_aliases_deleted(); -- =========================================== -- Tag search -- =========================================== CREATE TABLE tag_search ( tag_id UUID PRIMARY KEY REFERENCES tags(id) ON DELETE CASCADE, name TEXT, aliases TEXT[] ); INSERT INTO tag_search SELECT T.id, T.name, ARRAY_AGG(TA.alias) FILTER (WHERE TA.alias IS NOT NULL) FROM tags T LEFT JOIN tag_aliases TA ON TA.tag_id = T.id WHERE T.deleted = false GROUP BY T.id; CREATE INDEX tag_search_bm25_idx ON tag_search USING bm25 (tag_id, name, aliases) WITH (key_field='tag_id'); CREATE OR REPLACE FUNCTION upsert_tag_search(tid UUID) RETURNS VOID AS $$ BEGIN -- Remove from search if soft-deleted DELETE FROM tag_search WHERE tag_id = tid AND EXISTS (SELECT 1 FROM tags WHERE id = tid AND deleted = true); -- Insert/update only if not deleted INSERT INTO tag_search (tag_id, name, aliases) SELECT T.id, T.name, ARRAY_AGG(TA.alias) FILTER (WHERE TA.alias IS NOT NULL) FROM tags T LEFT JOIN tag_aliases TA ON TA.tag_id = T.id WHERE T.id = tid AND T.deleted = false GROUP BY T.id ON CONFLICT (tag_id) DO UPDATE SET name = EXCLUDED.name, aliases = EXCLUDED.aliases; END; $$ LANGUAGE plpgsql; -- On tag insert/update CREATE OR REPLACE FUNCTION trg_tag_changed() RETURNS TRIGGER AS $$ BEGIN PERFORM upsert_tag_search(NEW.id); RETURN NULL; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trg_tag_search_on_tag AFTER INSERT OR UPDATE ON tags FOR EACH ROW EXECUTE FUNCTION trg_tag_changed(); -- On tag_aliases insert CREATE OR REPLACE FUNCTION trg_tag_aliases_inserted() RETURNS TRIGGER AS $$ BEGIN PERFORM upsert_tag_search(tag_id) FROM (SELECT DISTINCT tag_id FROM new_rows) affected; RETURN NULL; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trg_tag_search_on_alias_insert AFTER INSERT ON tag_aliases REFERENCING NEW TABLE AS new_rows FOR EACH STATEMENT EXECUTE FUNCTION trg_tag_aliases_inserted(); -- On tag_aliases delete CREATE OR REPLACE FUNCTION trg_tag_aliases_deleted() RETURNS TRIGGER AS $$ BEGIN PERFORM upsert_tag_search(tag_id) FROM (SELECT DISTINCT tag_id FROM old_rows) affected; RETURN NULL; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trg_tag_search_on_alias_delete AFTER DELETE ON tag_aliases REFERENCING OLD TABLE AS old_rows FOR EACH STATEMENT EXECUTE FUNCTION trg_tag_aliases_deleted(); -- =========================================== -- Drop old trigram indexes -- =========================================== DROP INDEX IF EXISTS name_trgm_idx; DROP INDEX IF EXISTS disambiguation_trgm_idx; DROP INDEX IF EXISTS performer_alias_trgm_idx; ================================================ FILE: internal/database/migrations/postgres/57_mod_audit.up.sql ================================================ -- Create enum for moderator audit action types DROP TYPE IF EXISTS mod_audit_action; CREATE TYPE mod_audit_action AS ENUM ( 'EDIT_DELETE', 'EDIT_AMENDMENT' ); -- Create mod_audit table for tracking moderator actions CREATE TABLE mod_audit ( id UUID PRIMARY KEY, action mod_audit_action NOT NULL, user_id UUID REFERENCES users(id) ON DELETE SET NULL, target_id UUID NOT NULL, target_type VARCHAR(20) NOT NULL, data JSONB NOT NULL, reason TEXT, created_at TIMESTAMP NOT NULL DEFAULT NOW() ); -- Create indexes for common queries CREATE INDEX mod_audit_user_id_idx ON mod_audit(user_id); CREATE INDEX mod_audit_target_id_idx ON mod_audit(target_id); CREATE INDEX mod_audit_action_idx ON mod_audit(action); CREATE INDEX mod_audit_created_at_idx ON mod_audit(created_at DESC); -- Fix missing CASCADE on edit_votes ALTER TABLE edit_votes DROP CONSTRAINT IF EXISTS edit_votes_edit_id_fkey, ADD CONSTRAINT edit_votes_edit_id_fkey FOREIGN KEY (edit_id) REFERENCES edits(id) ON DELETE CASCADE; ================================================ FILE: internal/database/testutil/testutil.go ================================================ package testutil import ( "context" "fmt" "os" "testing" "github.com/jackc/pgx/v5/pgxpool" "github.com/stashapp/stash-box/internal/database" "github.com/stashapp/stash-box/internal/service" ) var ( db *pgxpool.Pool factory *service.Factory ) const defaultTestDB = "postgres@localhost/stash-box-test?sslmode=disable" type DatabasePopulater interface { PopulateDB(factory *service.Factory) error } func pgDropAll(conn *pgxpool.Pool) { // we want to drop all tables so that the migration initialises // the schema rows, err := conn.Query(context.TODO(), `select 'drop table if exists "' || tablename || '" cascade;' from pg_tables`) if err != nil { panic("Error dropping tables: " + err.Error()) } defer rows.Close() for rows.Next() { var stmt string if err := rows.Scan(&stmt); err != nil { panic("Error dropping tables: " + err.Error()) } _, _ = conn.Exec(context.TODO(), stmt) } } func initPostgres(connString string) func() { conn, err := pgxpool.New(context.TODO(), "postgres://"+connString) if err != nil { panic(fmt.Sprintf("Could not connect to postgres database at %s: %s", connString, err.Error())) } pgDropAll(conn) conn.Close() db = database.Initialize(connString) factory = service.NewFactory(db, nil) // nil EmailManager is fine for tests // Create system users (root, StashBot, etc.) just like main.go does factory.User().CreateSystemUsers(context.TODO()) return teardownPostgres } func teardownPostgres() { noDrop := os.Getenv("POSTGRES_NODROP") if noDrop == "" { pgDropAll(db) } db.Close() } func runTests(m *testing.M, populater DatabasePopulater) int { var deferFn func() pgConnStr := os.Getenv("POSTGRES_DB") if pgConnStr == "" { pgConnStr = defaultTestDB } deferFn = initPostgres(pgConnStr) // defer close and delete the database if deferFn != nil { defer deferFn() } if populater != nil { err := populater.PopulateDB(factory) if err != nil { panic(fmt.Sprintf("Could not populate database: %s", err.Error())) } } // run the tests return m.Run() } func TestWithDatabase(m *testing.M, populater DatabasePopulater) { ret := runTests(m, populater) os.Exit(ret) } func Factory() *service.Factory { return factory } ================================================ FILE: internal/dataloader/bodymodificationsloader_gen.go ================================================ // Code generated by github.com/vektah/dataloaden, DO NOT EDIT. package dataloader import ( "sync" "time" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" ) // BodyModificationsLoaderConfig captures the config to create a new BodyModificationsLoader type BodyModificationsLoaderConfig struct { // Fetch is a method that provides the data for the loader Fetch func(keys []uuid.UUID) ([][]models.BodyModification, []error) // Wait is how long wait before sending a batch Wait time.Duration // MaxBatch will limit the maximum number of keys to send in one batch, 0 = not limit MaxBatch int } // NewBodyModificationsLoader creates a new BodyModificationsLoader given a fetch, wait, and maxBatch func NewBodyModificationsLoader(config BodyModificationsLoaderConfig) *BodyModificationsLoader { return &BodyModificationsLoader{ fetch: config.Fetch, wait: config.Wait, maxBatch: config.MaxBatch, } } // BodyModificationsLoader batches and caches requests type BodyModificationsLoader struct { // this method provides the data for the loader fetch func(keys []uuid.UUID) ([][]models.BodyModification, []error) // how long to done before sending a batch wait time.Duration // this will limit the maximum number of keys to send in one batch, 0 = no limit maxBatch int // INTERNAL // lazily created cache cache map[uuid.UUID][]models.BodyModification // the current batch. keys will continue to be collected until timeout is hit, // then everything will be sent to the fetch method and out to the listeners batch *bodyModificationsLoaderBatch // mutex to prevent races mu sync.Mutex } type bodyModificationsLoaderBatch struct { keys []uuid.UUID data [][]models.BodyModification error []error closing bool done chan struct{} } // Load a BodyModification by key, batching and caching will be applied automatically func (l *BodyModificationsLoader) Load(key uuid.UUID) ([]models.BodyModification, error) { return l.LoadThunk(key)() } // LoadThunk returns a function that when called will block waiting for a BodyModification. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *BodyModificationsLoader) LoadThunk(key uuid.UUID) func() ([]models.BodyModification, error) { l.mu.Lock() if it, ok := l.cache[key]; ok { l.mu.Unlock() return func() ([]models.BodyModification, error) { return it, nil } } if l.batch == nil { l.batch = &bodyModificationsLoaderBatch{done: make(chan struct{})} } batch := l.batch pos := batch.keyIndex(l, key) l.mu.Unlock() return func() ([]models.BodyModification, error) { <-batch.done var data []models.BodyModification if pos < len(batch.data) { data = batch.data[pos] } var err error // its convenient to be able to return a single error for everything if len(batch.error) == 1 { err = batch.error[0] } else if batch.error != nil { err = batch.error[pos] } if err == nil { l.mu.Lock() l.unsafeSet(key, data) l.mu.Unlock() } return data, err } } // LoadAll fetches many keys at once. It will be broken into appropriate sized // sub batches depending on how the loader is configured func (l *BodyModificationsLoader) LoadAll(keys []uuid.UUID) ([][]models.BodyModification, []error) { results := make([]func() ([]models.BodyModification, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } bodyModifications := make([][]models.BodyModification, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { bodyModifications[i], errors[i] = thunk() } return bodyModifications, errors } // LoadAllThunk returns a function that when called will block waiting for a BodyModifications. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *BodyModificationsLoader) LoadAllThunk(keys []uuid.UUID) func() ([][]models.BodyModification, []error) { results := make([]func() ([]models.BodyModification, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } return func() ([][]models.BodyModification, []error) { bodyModifications := make([][]models.BodyModification, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { bodyModifications[i], errors[i] = thunk() } return bodyModifications, errors } } // Prime the cache with the provided key and value. If the key already exists, no change is made // and false is returned. // (To forcefully prime the cache, clear the key first with loader.clear(key).prime(key, value).) func (l *BodyModificationsLoader) Prime(key uuid.UUID, value []models.BodyModification) bool { l.mu.Lock() var found bool if _, found = l.cache[key]; !found { // make a copy when writing to the cache, its easy to pass a pointer in from a loop var // and end up with the whole cache pointing to the same value. cpy := make([]models.BodyModification, len(value)) copy(cpy, value) l.unsafeSet(key, cpy) } l.mu.Unlock() return !found } // Clear the value at key from the cache, if it exists func (l *BodyModificationsLoader) Clear(key uuid.UUID) { l.mu.Lock() delete(l.cache, key) l.mu.Unlock() } func (l *BodyModificationsLoader) unsafeSet(key uuid.UUID, value []models.BodyModification) { if l.cache == nil { l.cache = map[uuid.UUID][]models.BodyModification{} } l.cache[key] = value } // keyIndex will return the location of the key in the batch, if its not found // it will add the key to the batch func (b *bodyModificationsLoaderBatch) keyIndex(l *BodyModificationsLoader, key uuid.UUID) int { for i, existingKey := range b.keys { if key == existingKey { return i } } pos := len(b.keys) b.keys = append(b.keys, key) if pos == 0 { go b.startTimer(l) } if l.maxBatch != 0 && pos >= l.maxBatch-1 { if !b.closing { b.closing = true l.batch = nil go b.end(l) } } return pos } func (b *bodyModificationsLoaderBatch) startTimer(l *BodyModificationsLoader) { time.Sleep(l.wait) l.mu.Lock() // we must have hit a batch limit and are already finalizing this batch if b.closing { l.mu.Unlock() return } l.batch = nil l.mu.Unlock() b.end(l) } func (b *bodyModificationsLoaderBatch) end(l *BodyModificationsLoader) { b.data, b.error = l.fetch(b.keys) close(b.done) } ================================================ FILE: internal/dataloader/boolsloader_gen.go ================================================ // Code generated by github.com/vektah/dataloaden, DO NOT EDIT. package dataloader import ( "sync" "time" "github.com/gofrs/uuid" ) // BoolsLoaderConfig captures the config to create a new BoolsLoader type BoolsLoaderConfig struct { // Fetch is a method that provides the data for the loader Fetch func(keys []uuid.UUID) ([]bool, []error) // Wait is how long wait before sending a batch Wait time.Duration // MaxBatch will limit the maximum number of keys to send in one batch, 0 = not limit MaxBatch int } // NewBoolsLoader creates a new BoolsLoader given a fetch, wait, and maxBatch func NewBoolsLoader(config BoolsLoaderConfig) *BoolsLoader { return &BoolsLoader{ fetch: config.Fetch, wait: config.Wait, maxBatch: config.MaxBatch, } } // BoolsLoader batches and caches requests type BoolsLoader struct { // this method provides the data for the loader fetch func(keys []uuid.UUID) ([]bool, []error) // how long to done before sending a batch wait time.Duration // this will limit the maximum number of keys to send in one batch, 0 = no limit maxBatch int // INTERNAL // lazily created cache cache map[uuid.UUID]bool // the current batch. keys will continue to be collected until timeout is hit, // then everything will be sent to the fetch method and out to the listeners batch *boolsLoaderBatch // mutex to prevent races mu sync.Mutex } type boolsLoaderBatch struct { keys []uuid.UUID data []bool error []error closing bool done chan struct{} } // Load a bool by key, batching and caching will be applied automatically func (l *BoolsLoader) Load(key uuid.UUID) (bool, error) { return l.LoadThunk(key)() } // LoadThunk returns a function that when called will block waiting for a bool. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *BoolsLoader) LoadThunk(key uuid.UUID) func() (bool, error) { l.mu.Lock() if it, ok := l.cache[key]; ok { l.mu.Unlock() return func() (bool, error) { return it, nil } } if l.batch == nil { l.batch = &boolsLoaderBatch{done: make(chan struct{})} } batch := l.batch pos := batch.keyIndex(l, key) l.mu.Unlock() return func() (bool, error) { <-batch.done var data bool if pos < len(batch.data) { data = batch.data[pos] } var err error // its convenient to be able to return a single error for everything if len(batch.error) == 1 { err = batch.error[0] } else if batch.error != nil { err = batch.error[pos] } if err == nil { l.mu.Lock() l.unsafeSet(key, data) l.mu.Unlock() } return data, err } } // LoadAll fetches many keys at once. It will be broken into appropriate sized // sub batches depending on how the loader is configured func (l *BoolsLoader) LoadAll(keys []uuid.UUID) ([]bool, []error) { results := make([]func() (bool, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } bools := make([]bool, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { bools[i], errors[i] = thunk() } return bools, errors } // LoadAllThunk returns a function that when called will block waiting for a bools. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *BoolsLoader) LoadAllThunk(keys []uuid.UUID) func() ([]bool, []error) { results := make([]func() (bool, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } return func() ([]bool, []error) { bools := make([]bool, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { bools[i], errors[i] = thunk() } return bools, errors } } // Prime the cache with the provided key and value. If the key already exists, no change is made // and false is returned. // (To forcefully prime the cache, clear the key first with loader.clear(key).prime(key, value).) func (l *BoolsLoader) Prime(key uuid.UUID, value bool) bool { l.mu.Lock() var found bool if _, found = l.cache[key]; !found { l.unsafeSet(key, value) } l.mu.Unlock() return !found } // Clear the value at key from the cache, if it exists func (l *BoolsLoader) Clear(key uuid.UUID) { l.mu.Lock() delete(l.cache, key) l.mu.Unlock() } func (l *BoolsLoader) unsafeSet(key uuid.UUID, value bool) { if l.cache == nil { l.cache = map[uuid.UUID]bool{} } l.cache[key] = value } // keyIndex will return the location of the key in the batch, if its not found // it will add the key to the batch func (b *boolsLoaderBatch) keyIndex(l *BoolsLoader, key uuid.UUID) int { for i, existingKey := range b.keys { if key == existingKey { return i } } pos := len(b.keys) b.keys = append(b.keys, key) if pos == 0 { go b.startTimer(l) } if l.maxBatch != 0 && pos >= l.maxBatch-1 { if !b.closing { b.closing = true l.batch = nil go b.end(l) } } return pos } func (b *boolsLoaderBatch) startTimer(l *BoolsLoader) { time.Sleep(l.wait) l.mu.Lock() // we must have hit a batch limit and are already finalizing this batch if b.closing { l.mu.Unlock() return } l.batch = nil l.mu.Unlock() b.end(l) } func (b *boolsLoaderBatch) end(l *BoolsLoader) { b.data, b.error = l.fetch(b.keys) close(b.done) } ================================================ FILE: internal/dataloader/editcommentloader_gen.go ================================================ // Code generated by github.com/vektah/dataloaden, DO NOT EDIT. package dataloader import ( "sync" "time" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" ) // EditCommentLoaderConfig captures the config to create a new EditCommentLoader type EditCommentLoaderConfig struct { // Fetch is a method that provides the data for the loader Fetch func(keys []uuid.UUID) ([]*models.EditComment, []error) // Wait is how long wait before sending a batch Wait time.Duration // MaxBatch will limit the maximum number of keys to send in one batch, 0 = not limit MaxBatch int } // NewEditCommentLoader creates a new EditCommentLoader given a fetch, wait, and maxBatch func NewEditCommentLoader(config EditCommentLoaderConfig) *EditCommentLoader { return &EditCommentLoader{ fetch: config.Fetch, wait: config.Wait, maxBatch: config.MaxBatch, } } // EditCommentLoader batches and caches requests type EditCommentLoader struct { // this method provides the data for the loader fetch func(keys []uuid.UUID) ([]*models.EditComment, []error) // how long to done before sending a batch wait time.Duration // this will limit the maximum number of keys to send in one batch, 0 = no limit maxBatch int // INTERNAL // lazily created cache cache map[uuid.UUID]*models.EditComment // the current batch. keys will continue to be collected until timeout is hit, // then everything will be sent to the fetch method and out to the listeners batch *editCommentLoaderBatch // mutex to prevent races mu sync.Mutex } type editCommentLoaderBatch struct { keys []uuid.UUID data []*models.EditComment error []error closing bool done chan struct{} } // Load a EditComment by key, batching and caching will be applied automatically func (l *EditCommentLoader) Load(key uuid.UUID) (*models.EditComment, error) { return l.LoadThunk(key)() } // LoadThunk returns a function that when called will block waiting for a EditComment. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *EditCommentLoader) LoadThunk(key uuid.UUID) func() (*models.EditComment, error) { l.mu.Lock() if it, ok := l.cache[key]; ok { l.mu.Unlock() return func() (*models.EditComment, error) { return it, nil } } if l.batch == nil { l.batch = &editCommentLoaderBatch{done: make(chan struct{})} } batch := l.batch pos := batch.keyIndex(l, key) l.mu.Unlock() return func() (*models.EditComment, error) { <-batch.done var data *models.EditComment if pos < len(batch.data) { data = batch.data[pos] } var err error // its convenient to be able to return a single error for everything if len(batch.error) == 1 { err = batch.error[0] } else if batch.error != nil { err = batch.error[pos] } if err == nil { l.mu.Lock() l.unsafeSet(key, data) l.mu.Unlock() } return data, err } } // LoadAll fetches many keys at once. It will be broken into appropriate sized // sub batches depending on how the loader is configured func (l *EditCommentLoader) LoadAll(keys []uuid.UUID) ([]*models.EditComment, []error) { results := make([]func() (*models.EditComment, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } editComments := make([]*models.EditComment, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { editComments[i], errors[i] = thunk() } return editComments, errors } // LoadAllThunk returns a function that when called will block waiting for a EditComments. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *EditCommentLoader) LoadAllThunk(keys []uuid.UUID) func() ([]*models.EditComment, []error) { results := make([]func() (*models.EditComment, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } return func() ([]*models.EditComment, []error) { editComments := make([]*models.EditComment, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { editComments[i], errors[i] = thunk() } return editComments, errors } } // Prime the cache with the provided key and value. If the key already exists, no change is made // and false is returned. // (To forcefully prime the cache, clear the key first with loader.clear(key).prime(key, value).) func (l *EditCommentLoader) Prime(key uuid.UUID, value *models.EditComment) bool { l.mu.Lock() var found bool if _, found = l.cache[key]; !found { // make a copy when writing to the cache, its easy to pass a pointer in from a loop var // and end up with the whole cache pointing to the same value. cpy := *value l.unsafeSet(key, &cpy) } l.mu.Unlock() return !found } // Clear the value at key from the cache, if it exists func (l *EditCommentLoader) Clear(key uuid.UUID) { l.mu.Lock() delete(l.cache, key) l.mu.Unlock() } func (l *EditCommentLoader) unsafeSet(key uuid.UUID, value *models.EditComment) { if l.cache == nil { l.cache = map[uuid.UUID]*models.EditComment{} } l.cache[key] = value } // keyIndex will return the location of the key in the batch, if its not found // it will add the key to the batch func (b *editCommentLoaderBatch) keyIndex(l *EditCommentLoader, key uuid.UUID) int { for i, existingKey := range b.keys { if key == existingKey { return i } } pos := len(b.keys) b.keys = append(b.keys, key) if pos == 0 { go b.startTimer(l) } if l.maxBatch != 0 && pos >= l.maxBatch-1 { if !b.closing { b.closing = true l.batch = nil go b.end(l) } } return pos } func (b *editCommentLoaderBatch) startTimer(l *EditCommentLoader) { time.Sleep(l.wait) l.mu.Lock() // we must have hit a batch limit and are already finalizing this batch if b.closing { l.mu.Unlock() return } l.batch = nil l.mu.Unlock() b.end(l) } func (b *editCommentLoaderBatch) end(l *EditCommentLoader) { b.data, b.error = l.fetch(b.keys) close(b.done) } ================================================ FILE: internal/dataloader/editloader_gen.go ================================================ // Code generated by github.com/vektah/dataloaden, DO NOT EDIT. package dataloader import ( "sync" "time" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" ) // EditLoaderConfig captures the config to create a new EditLoader type EditLoaderConfig struct { // Fetch is a method that provides the data for the loader Fetch func(keys []uuid.UUID) ([]*models.Edit, []error) // Wait is how long wait before sending a batch Wait time.Duration // MaxBatch will limit the maximum number of keys to send in one batch, 0 = not limit MaxBatch int } // NewEditLoader creates a new EditLoader given a fetch, wait, and maxBatch func NewEditLoader(config EditLoaderConfig) *EditLoader { return &EditLoader{ fetch: config.Fetch, wait: config.Wait, maxBatch: config.MaxBatch, } } // EditLoader batches and caches requests type EditLoader struct { // this method provides the data for the loader fetch func(keys []uuid.UUID) ([]*models.Edit, []error) // how long to done before sending a batch wait time.Duration // this will limit the maximum number of keys to send in one batch, 0 = no limit maxBatch int // INTERNAL // lazily created cache cache map[uuid.UUID]*models.Edit // the current batch. keys will continue to be collected until timeout is hit, // then everything will be sent to the fetch method and out to the listeners batch *editLoaderBatch // mutex to prevent races mu sync.Mutex } type editLoaderBatch struct { keys []uuid.UUID data []*models.Edit error []error closing bool done chan struct{} } // Load a Edit by key, batching and caching will be applied automatically func (l *EditLoader) Load(key uuid.UUID) (*models.Edit, error) { return l.LoadThunk(key)() } // LoadThunk returns a function that when called will block waiting for a Edit. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *EditLoader) LoadThunk(key uuid.UUID) func() (*models.Edit, error) { l.mu.Lock() if it, ok := l.cache[key]; ok { l.mu.Unlock() return func() (*models.Edit, error) { return it, nil } } if l.batch == nil { l.batch = &editLoaderBatch{done: make(chan struct{})} } batch := l.batch pos := batch.keyIndex(l, key) l.mu.Unlock() return func() (*models.Edit, error) { <-batch.done var data *models.Edit if pos < len(batch.data) { data = batch.data[pos] } var err error // its convenient to be able to return a single error for everything if len(batch.error) == 1 { err = batch.error[0] } else if batch.error != nil { err = batch.error[pos] } if err == nil { l.mu.Lock() l.unsafeSet(key, data) l.mu.Unlock() } return data, err } } // LoadAll fetches many keys at once. It will be broken into appropriate sized // sub batches depending on how the loader is configured func (l *EditLoader) LoadAll(keys []uuid.UUID) ([]*models.Edit, []error) { results := make([]func() (*models.Edit, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } edits := make([]*models.Edit, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { edits[i], errors[i] = thunk() } return edits, errors } // LoadAllThunk returns a function that when called will block waiting for a Edits. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *EditLoader) LoadAllThunk(keys []uuid.UUID) func() ([]*models.Edit, []error) { results := make([]func() (*models.Edit, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } return func() ([]*models.Edit, []error) { edits := make([]*models.Edit, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { edits[i], errors[i] = thunk() } return edits, errors } } // Prime the cache with the provided key and value. If the key already exists, no change is made // and false is returned. // (To forcefully prime the cache, clear the key first with loader.clear(key).prime(key, value).) func (l *EditLoader) Prime(key uuid.UUID, value *models.Edit) bool { l.mu.Lock() var found bool if _, found = l.cache[key]; !found { // make a copy when writing to the cache, its easy to pass a pointer in from a loop var // and end up with the whole cache pointing to the same value. cpy := *value l.unsafeSet(key, &cpy) } l.mu.Unlock() return !found } // Clear the value at key from the cache, if it exists func (l *EditLoader) Clear(key uuid.UUID) { l.mu.Lock() delete(l.cache, key) l.mu.Unlock() } func (l *EditLoader) unsafeSet(key uuid.UUID, value *models.Edit) { if l.cache == nil { l.cache = map[uuid.UUID]*models.Edit{} } l.cache[key] = value } // keyIndex will return the location of the key in the batch, if its not found // it will add the key to the batch func (b *editLoaderBatch) keyIndex(l *EditLoader, key uuid.UUID) int { for i, existingKey := range b.keys { if key == existingKey { return i } } pos := len(b.keys) b.keys = append(b.keys, key) if pos == 0 { go b.startTimer(l) } if l.maxBatch != 0 && pos >= l.maxBatch-1 { if !b.closing { b.closing = true l.batch = nil go b.end(l) } } return pos } func (b *editLoaderBatch) startTimer(l *EditLoader) { time.Sleep(l.wait) l.mu.Lock() // we must have hit a batch limit and are already finalizing this batch if b.closing { l.mu.Unlock() return } l.batch = nil l.mu.Unlock() b.end(l) } func (b *editLoaderBatch) end(l *EditLoader) { b.data, b.error = l.fetch(b.keys) close(b.done) } ================================================ FILE: internal/dataloader/fingerprintsloader_gen.go ================================================ // Code generated by github.com/vektah/dataloaden, DO NOT EDIT. package dataloader import ( "sync" "time" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" ) // FingerprintsLoaderConfig captures the config to create a new FingerprintsLoader type FingerprintsLoaderConfig struct { // Fetch is a method that provides the data for the loader Fetch func(keys []uuid.UUID) ([][]models.Fingerprint, []error) // Wait is how long wait before sending a batch Wait time.Duration // MaxBatch will limit the maximum number of keys to send in one batch, 0 = not limit MaxBatch int } // NewFingerprintsLoader creates a new FingerprintsLoader given a fetch, wait, and maxBatch func NewFingerprintsLoader(config FingerprintsLoaderConfig) *FingerprintsLoader { return &FingerprintsLoader{ fetch: config.Fetch, wait: config.Wait, maxBatch: config.MaxBatch, } } // FingerprintsLoader batches and caches requests type FingerprintsLoader struct { // this method provides the data for the loader fetch func(keys []uuid.UUID) ([][]models.Fingerprint, []error) // how long to done before sending a batch wait time.Duration // this will limit the maximum number of keys to send in one batch, 0 = no limit maxBatch int // INTERNAL // lazily created cache cache map[uuid.UUID][]models.Fingerprint // the current batch. keys will continue to be collected until timeout is hit, // then everything will be sent to the fetch method and out to the listeners batch *fingerprintsLoaderBatch // mutex to prevent races mu sync.Mutex } type fingerprintsLoaderBatch struct { keys []uuid.UUID data [][]models.Fingerprint error []error closing bool done chan struct{} } // Load a Fingerprint by key, batching and caching will be applied automatically func (l *FingerprintsLoader) Load(key uuid.UUID) ([]models.Fingerprint, error) { return l.LoadThunk(key)() } // LoadThunk returns a function that when called will block waiting for a Fingerprint. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *FingerprintsLoader) LoadThunk(key uuid.UUID) func() ([]models.Fingerprint, error) { l.mu.Lock() if it, ok := l.cache[key]; ok { l.mu.Unlock() return func() ([]models.Fingerprint, error) { return it, nil } } if l.batch == nil { l.batch = &fingerprintsLoaderBatch{done: make(chan struct{})} } batch := l.batch pos := batch.keyIndex(l, key) l.mu.Unlock() return func() ([]models.Fingerprint, error) { <-batch.done var data []models.Fingerprint if pos < len(batch.data) { data = batch.data[pos] } var err error // its convenient to be able to return a single error for everything if len(batch.error) == 1 { err = batch.error[0] } else if batch.error != nil { err = batch.error[pos] } if err == nil { l.mu.Lock() l.unsafeSet(key, data) l.mu.Unlock() } return data, err } } // LoadAll fetches many keys at once. It will be broken into appropriate sized // sub batches depending on how the loader is configured func (l *FingerprintsLoader) LoadAll(keys []uuid.UUID) ([][]models.Fingerprint, []error) { results := make([]func() ([]models.Fingerprint, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } fingerprints := make([][]models.Fingerprint, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { fingerprints[i], errors[i] = thunk() } return fingerprints, errors } // LoadAllThunk returns a function that when called will block waiting for a Fingerprints. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *FingerprintsLoader) LoadAllThunk(keys []uuid.UUID) func() ([][]models.Fingerprint, []error) { results := make([]func() ([]models.Fingerprint, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } return func() ([][]models.Fingerprint, []error) { fingerprints := make([][]models.Fingerprint, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { fingerprints[i], errors[i] = thunk() } return fingerprints, errors } } // Prime the cache with the provided key and value. If the key already exists, no change is made // and false is returned. // (To forcefully prime the cache, clear the key first with loader.clear(key).prime(key, value).) func (l *FingerprintsLoader) Prime(key uuid.UUID, value []models.Fingerprint) bool { l.mu.Lock() var found bool if _, found = l.cache[key]; !found { // make a copy when writing to the cache, its easy to pass a pointer in from a loop var // and end up with the whole cache pointing to the same value. cpy := make([]models.Fingerprint, len(value)) copy(cpy, value) l.unsafeSet(key, cpy) } l.mu.Unlock() return !found } // Clear the value at key from the cache, if it exists func (l *FingerprintsLoader) Clear(key uuid.UUID) { l.mu.Lock() delete(l.cache, key) l.mu.Unlock() } func (l *FingerprintsLoader) unsafeSet(key uuid.UUID, value []models.Fingerprint) { if l.cache == nil { l.cache = map[uuid.UUID][]models.Fingerprint{} } l.cache[key] = value } // keyIndex will return the location of the key in the batch, if its not found // it will add the key to the batch func (b *fingerprintsLoaderBatch) keyIndex(l *FingerprintsLoader, key uuid.UUID) int { for i, existingKey := range b.keys { if key == existingKey { return i } } pos := len(b.keys) b.keys = append(b.keys, key) if pos == 0 { go b.startTimer(l) } if l.maxBatch != 0 && pos >= l.maxBatch-1 { if !b.closing { b.closing = true l.batch = nil go b.end(l) } } return pos } func (b *fingerprintsLoaderBatch) startTimer(l *FingerprintsLoader) { time.Sleep(l.wait) l.mu.Lock() // we must have hit a batch limit and are already finalizing this batch if b.closing { l.mu.Unlock() return } l.batch = nil l.mu.Unlock() b.end(l) } func (b *fingerprintsLoaderBatch) end(l *FingerprintsLoader) { b.data, b.error = l.fetch(b.keys) close(b.done) } ================================================ FILE: internal/dataloader/imageloader_gen.go ================================================ // Code generated by github.com/vektah/dataloaden, DO NOT EDIT. package dataloader import ( "sync" "time" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" ) // ImageLoaderConfig captures the config to create a new ImageLoader type ImageLoaderConfig struct { // Fetch is a method that provides the data for the loader Fetch func(keys []uuid.UUID) ([]*models.Image, []error) // Wait is how long wait before sending a batch Wait time.Duration // MaxBatch will limit the maximum number of keys to send in one batch, 0 = not limit MaxBatch int } // NewImageLoader creates a new ImageLoader given a fetch, wait, and maxBatch func NewImageLoader(config ImageLoaderConfig) *ImageLoader { return &ImageLoader{ fetch: config.Fetch, wait: config.Wait, maxBatch: config.MaxBatch, } } // ImageLoader batches and caches requests type ImageLoader struct { // this method provides the data for the loader fetch func(keys []uuid.UUID) ([]*models.Image, []error) // how long to done before sending a batch wait time.Duration // this will limit the maximum number of keys to send in one batch, 0 = no limit maxBatch int // INTERNAL // lazily created cache cache map[uuid.UUID]*models.Image // the current batch. keys will continue to be collected until timeout is hit, // then everything will be sent to the fetch method and out to the listeners batch *imageLoaderBatch // mutex to prevent races mu sync.Mutex } type imageLoaderBatch struct { keys []uuid.UUID data []*models.Image error []error closing bool done chan struct{} } // Load a Image by key, batching and caching will be applied automatically func (l *ImageLoader) Load(key uuid.UUID) (*models.Image, error) { return l.LoadThunk(key)() } // LoadThunk returns a function that when called will block waiting for a Image. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *ImageLoader) LoadThunk(key uuid.UUID) func() (*models.Image, error) { l.mu.Lock() if it, ok := l.cache[key]; ok { l.mu.Unlock() return func() (*models.Image, error) { return it, nil } } if l.batch == nil { l.batch = &imageLoaderBatch{done: make(chan struct{})} } batch := l.batch pos := batch.keyIndex(l, key) l.mu.Unlock() return func() (*models.Image, error) { <-batch.done var data *models.Image if pos < len(batch.data) { data = batch.data[pos] } var err error // its convenient to be able to return a single error for everything if len(batch.error) == 1 { err = batch.error[0] } else if batch.error != nil { err = batch.error[pos] } if err == nil { l.mu.Lock() l.unsafeSet(key, data) l.mu.Unlock() } return data, err } } // LoadAll fetches many keys at once. It will be broken into appropriate sized // sub batches depending on how the loader is configured func (l *ImageLoader) LoadAll(keys []uuid.UUID) ([]*models.Image, []error) { results := make([]func() (*models.Image, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } images := make([]*models.Image, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { images[i], errors[i] = thunk() } return images, errors } // LoadAllThunk returns a function that when called will block waiting for a Images. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *ImageLoader) LoadAllThunk(keys []uuid.UUID) func() ([]*models.Image, []error) { results := make([]func() (*models.Image, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } return func() ([]*models.Image, []error) { images := make([]*models.Image, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { images[i], errors[i] = thunk() } return images, errors } } // Prime the cache with the provided key and value. If the key already exists, no change is made // and false is returned. // (To forcefully prime the cache, clear the key first with loader.clear(key).prime(key, value).) func (l *ImageLoader) Prime(key uuid.UUID, value *models.Image) bool { l.mu.Lock() var found bool if _, found = l.cache[key]; !found { // make a copy when writing to the cache, its easy to pass a pointer in from a loop var // and end up with the whole cache pointing to the same value. cpy := *value l.unsafeSet(key, &cpy) } l.mu.Unlock() return !found } // Clear the value at key from the cache, if it exists func (l *ImageLoader) Clear(key uuid.UUID) { l.mu.Lock() delete(l.cache, key) l.mu.Unlock() } func (l *ImageLoader) unsafeSet(key uuid.UUID, value *models.Image) { if l.cache == nil { l.cache = map[uuid.UUID]*models.Image{} } l.cache[key] = value } // keyIndex will return the location of the key in the batch, if its not found // it will add the key to the batch func (b *imageLoaderBatch) keyIndex(l *ImageLoader, key uuid.UUID) int { for i, existingKey := range b.keys { if key == existingKey { return i } } pos := len(b.keys) b.keys = append(b.keys, key) if pos == 0 { go b.startTimer(l) } if l.maxBatch != 0 && pos >= l.maxBatch-1 { if !b.closing { b.closing = true l.batch = nil go b.end(l) } } return pos } func (b *imageLoaderBatch) startTimer(l *ImageLoader) { time.Sleep(l.wait) l.mu.Lock() // we must have hit a batch limit and are already finalizing this batch if b.closing { l.mu.Unlock() return } l.batch = nil l.mu.Unlock() b.end(l) } func (b *imageLoaderBatch) end(l *ImageLoader) { b.data, b.error = l.fetch(b.keys) close(b.done) } ================================================ FILE: internal/dataloader/loaders.go ================================================ package dataloader import ( "context" "net/http" "time" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/auth" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/internal/service" ) type contextKey int const ( loadersKey contextKey = iota ) type Loaders struct { SceneFingerprintsByID FingerprintsLoader SubmittedSceneFingerprintsByID FingerprintsLoader ImageByID ImageLoader PerformerByID PerformerLoader PerformerAliasesByID StringsLoader PerformerImageIDsByID UUIDsLoader PerformerMergeIDsByID UUIDsLoader PerformerMergeIDsBySourceID UUIDsLoader PerformerPiercingsByID BodyModificationsLoader PerformerTattoosByID BodyModificationsLoader PerformerUrlsByID URLLoader PerformerIsFavoriteByID BoolsLoader SceneByID SceneLoader SceneImageIDsByID UUIDsLoader SceneAppearancesByID SceneAppearancesLoader SceneUrlsByID URLLoader StudioImageIDsByID UUIDsLoader StudioIsFavoriteByID BoolsLoader StudioUrlsByID URLLoader StudioAliasesByID StringsLoader SceneTagIDsByID UUIDsLoader SiteByID SiteLoader StudioByID StudioLoader TagByID TagLoader TagCategoryByID TagCategoryLoader EditByID EditLoader EditCommentByID EditCommentLoader } func Middleware(fac service.Factory) func(next http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() ctx = context.WithValue(ctx, loadersKey, GetLoaders(r.Context(), fac)) r = r.WithContext(ctx) next.ServeHTTP(w, r) }) } } func For(ctx context.Context) *Loaders { return ctx.Value(loadersKey).(*Loaders) } func GetLoadersKey() contextKey { return loadersKey } func GetLoaders(ctx context.Context, fac service.Factory) *Loaders { currentUser := auth.GetCurrentUser(ctx) return &Loaders{ SceneFingerprintsByID: FingerprintsLoader{ maxBatch: 100, wait: 1 * time.Millisecond, fetch: func(ids []uuid.UUID) ([][]models.Fingerprint, []error) { s := fac.Scene() return s.LoadFingerprints(ctx, currentUser.ID, ids, false) }, }, SubmittedSceneFingerprintsByID: FingerprintsLoader{ maxBatch: 100, wait: 1 * time.Millisecond, fetch: func(ids []uuid.UUID) ([][]models.Fingerprint, []error) { s := fac.Scene() return s.LoadFingerprints(ctx, currentUser.ID, ids, true) }, }, PerformerByID: PerformerLoader{ maxBatch: 100, wait: 1 * time.Millisecond, fetch: func(ids []uuid.UUID) ([]*models.Performer, []error) { s := fac.Performer() return s.LoadByIds(ctx, ids) }, }, SceneImageIDsByID: UUIDsLoader{ maxBatch: 100, wait: 1 * time.Millisecond, fetch: func(ids []uuid.UUID) ([][]uuid.UUID, []error) { s := fac.Image() return s.LoadBySceneIds(ctx, ids) }, }, PerformerImageIDsByID: UUIDsLoader{ maxBatch: 100, wait: 1 * time.Millisecond, fetch: func(ids []uuid.UUID) ([][]uuid.UUID, []error) { s := fac.Image() return s.LoadByPerformerIds(ctx, ids) }, }, PerformerMergeIDsByID: UUIDsLoader{ maxBatch: 100, wait: 1 * time.Millisecond, fetch: func(ids []uuid.UUID) ([][]uuid.UUID, []error) { s := fac.Performer() return s.LoadMergeIDsByPerformerIDs(ctx, ids) }, }, PerformerMergeIDsBySourceID: UUIDsLoader{ maxBatch: 100, wait: 1 * time.Millisecond, fetch: func(ids []uuid.UUID) ([][]uuid.UUID, []error) { s := fac.Performer() return s.LoadMergeIDsBySourcePerformerIDs(ctx, ids) }, }, PerformerAliasesByID: StringsLoader{ maxBatch: 100, wait: 1 * time.Millisecond, fetch: func(ids []uuid.UUID) ([][]string, []error) { s := fac.Performer() return s.LoadAliases(ctx, ids) }, }, PerformerTattoosByID: BodyModificationsLoader{ maxBatch: 100, wait: 1 * time.Millisecond, fetch: func(ids []uuid.UUID) ([][]models.BodyModification, []error) { s := fac.Performer() return s.LoadTattoos(ctx, ids) }, }, PerformerPiercingsByID: BodyModificationsLoader{ maxBatch: 100, wait: 1 * time.Millisecond, fetch: func(ids []uuid.UUID) ([][]models.BodyModification, []error) { s := fac.Performer() return s.LoadPiercings(ctx, ids) }, }, SceneAppearancesByID: SceneAppearancesLoader{ maxBatch: 100, wait: 1 * time.Millisecond, fetch: func(ids []uuid.UUID) ([][]models.PerformerScene, []error) { s := fac.Scene() return s.LoadAppearances(ctx, ids) }, }, SceneUrlsByID: URLLoader{ maxBatch: 100, wait: 1 * time.Millisecond, fetch: func(ids []uuid.UUID) ([][]models.URL, []error) { s := fac.Scene() return s.LoadURLs(ctx, ids) }, }, PerformerUrlsByID: URLLoader{ maxBatch: 100, wait: 1 * time.Millisecond, fetch: func(ids []uuid.UUID) ([][]models.URL, []error) { s := fac.Performer() return s.LoadURLs(ctx, ids) }, }, StudioUrlsByID: URLLoader{ maxBatch: 100, wait: 1 * time.Millisecond, fetch: func(ids []uuid.UUID) ([][]models.URL, []error) { s := fac.Studio() return s.LoadURLs(ctx, ids) }, }, ImageByID: ImageLoader{ maxBatch: 1000, wait: 1 * time.Millisecond, fetch: func(ids []uuid.UUID) ([]*models.Image, []error) { s := fac.Image() return s.LoadIds(ctx, ids) }, }, StudioImageIDsByID: UUIDsLoader{ maxBatch: 100, wait: 1 * time.Millisecond, fetch: func(ids []uuid.UUID) ([][]uuid.UUID, []error) { s := fac.Image() return s.LoadByStudioIds(ctx, ids) }, }, SceneTagIDsByID: UUIDsLoader{ maxBatch: 100, wait: 1 * time.Millisecond, fetch: func(ids []uuid.UUID) ([][]uuid.UUID, []error) { s := fac.Tag() return s.FindIdsBySceneIds(ctx, ids) }, }, SiteByID: SiteLoader{ maxBatch: 1000, wait: 1 * time.Millisecond, fetch: func(ids []uuid.UUID) ([]*models.Site, []error) { s := fac.Site() return s.LoadIds(ctx, ids) }, }, StudioByID: StudioLoader{ maxBatch: 1000, wait: 1 * time.Millisecond, fetch: func(ids []uuid.UUID) ([]*models.Studio, []error) { s := fac.Studio() return s.LoadIds(ctx, ids) }, }, TagByID: TagLoader{ maxBatch: 1000, wait: 1 * time.Millisecond, fetch: func(ids []uuid.UUID) ([]*models.Tag, []error) { s := fac.Tag() return s.LoadIds(ctx, ids) }, }, TagCategoryByID: TagCategoryLoader{ maxBatch: 1000, wait: 1 * time.Millisecond, fetch: func(ids []uuid.UUID) ([]*models.TagCategory, []error) { s := fac.Tag() return s.LoadCategoriesByIds(ctx, ids) }, }, EditByID: EditLoader{ maxBatch: 1000, wait: 1 * time.Millisecond, fetch: func(ids []uuid.UUID) ([]*models.Edit, []error) { s := fac.Edit() return s.LoadIds(ctx, ids) }, }, EditCommentByID: EditCommentLoader{ maxBatch: 1000, wait: 1 * time.Millisecond, fetch: func(ids []uuid.UUID) ([]*models.EditComment, []error) { s := fac.Edit() return s.LoadCommentsByIds(ctx, ids) }, }, SceneByID: SceneLoader{ maxBatch: 1000, wait: 1 * time.Millisecond, fetch: func(ids []uuid.UUID) ([]*models.Scene, []error) { s := fac.Scene() return s.LoadIds(ctx, ids) }, }, PerformerIsFavoriteByID: BoolsLoader{ maxBatch: 1000, wait: 1 * time.Millisecond, fetch: func(ids []uuid.UUID) ([]bool, []error) { s := fac.Performer() return s.LoadIsFavorite(ctx, currentUser.ID, ids) }, }, StudioIsFavoriteByID: BoolsLoader{ maxBatch: 1000, wait: 1 * time.Millisecond, fetch: func(ids []uuid.UUID) ([]bool, []error) { s := fac.Studio() return s.LoadIsFavorite(ctx, currentUser.ID, ids) }, }, StudioAliasesByID: StringsLoader{ maxBatch: 100, wait: 1 * time.Millisecond, fetch: func(ids []uuid.UUID) ([][]string, []error) { s := fac.Studio() return s.LoadAliases(ctx, ids) }, }, } } ================================================ FILE: internal/dataloader/performerloader_gen.go ================================================ // Code generated by github.com/vektah/dataloaden, DO NOT EDIT. package dataloader import ( "sync" "time" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" ) // PerformerLoaderConfig captures the config to create a new PerformerLoader type PerformerLoaderConfig struct { // Fetch is a method that provides the data for the loader Fetch func(keys []uuid.UUID) ([]*models.Performer, []error) // Wait is how long wait before sending a batch Wait time.Duration // MaxBatch will limit the maximum number of keys to send in one batch, 0 = not limit MaxBatch int } // NewPerformerLoader creates a new PerformerLoader given a fetch, wait, and maxBatch func NewPerformerLoader(config PerformerLoaderConfig) *PerformerLoader { return &PerformerLoader{ fetch: config.Fetch, wait: config.Wait, maxBatch: config.MaxBatch, } } // PerformerLoader batches and caches requests type PerformerLoader struct { // this method provides the data for the loader fetch func(keys []uuid.UUID) ([]*models.Performer, []error) // how long to done before sending a batch wait time.Duration // this will limit the maximum number of keys to send in one batch, 0 = no limit maxBatch int // INTERNAL // lazily created cache cache map[uuid.UUID]*models.Performer // the current batch. keys will continue to be collected until timeout is hit, // then everything will be sent to the fetch method and out to the listeners batch *performerLoaderBatch // mutex to prevent races mu sync.Mutex } type performerLoaderBatch struct { keys []uuid.UUID data []*models.Performer error []error closing bool done chan struct{} } // Load a Performer by key, batching and caching will be applied automatically func (l *PerformerLoader) Load(key uuid.UUID) (*models.Performer, error) { return l.LoadThunk(key)() } // LoadThunk returns a function that when called will block waiting for a Performer. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *PerformerLoader) LoadThunk(key uuid.UUID) func() (*models.Performer, error) { l.mu.Lock() if it, ok := l.cache[key]; ok { l.mu.Unlock() return func() (*models.Performer, error) { return it, nil } } if l.batch == nil { l.batch = &performerLoaderBatch{done: make(chan struct{})} } batch := l.batch pos := batch.keyIndex(l, key) l.mu.Unlock() return func() (*models.Performer, error) { <-batch.done var data *models.Performer if pos < len(batch.data) { data = batch.data[pos] } var err error // its convenient to be able to return a single error for everything if len(batch.error) == 1 { err = batch.error[0] } else if batch.error != nil { err = batch.error[pos] } if err == nil { l.mu.Lock() l.unsafeSet(key, data) l.mu.Unlock() } return data, err } } // LoadAll fetches many keys at once. It will be broken into appropriate sized // sub batches depending on how the loader is configured func (l *PerformerLoader) LoadAll(keys []uuid.UUID) ([]*models.Performer, []error) { results := make([]func() (*models.Performer, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } performers := make([]*models.Performer, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { performers[i], errors[i] = thunk() } return performers, errors } // LoadAllThunk returns a function that when called will block waiting for a Performers. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *PerformerLoader) LoadAllThunk(keys []uuid.UUID) func() ([]*models.Performer, []error) { results := make([]func() (*models.Performer, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } return func() ([]*models.Performer, []error) { performers := make([]*models.Performer, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { performers[i], errors[i] = thunk() } return performers, errors } } // Prime the cache with the provided key and value. If the key already exists, no change is made // and false is returned. // (To forcefully prime the cache, clear the key first with loader.clear(key).prime(key, value).) func (l *PerformerLoader) Prime(key uuid.UUID, value *models.Performer) bool { l.mu.Lock() var found bool if _, found = l.cache[key]; !found { // make a copy when writing to the cache, its easy to pass a pointer in from a loop var // and end up with the whole cache pointing to the same value. cpy := *value l.unsafeSet(key, &cpy) } l.mu.Unlock() return !found } // Clear the value at key from the cache, if it exists func (l *PerformerLoader) Clear(key uuid.UUID) { l.mu.Lock() delete(l.cache, key) l.mu.Unlock() } func (l *PerformerLoader) unsafeSet(key uuid.UUID, value *models.Performer) { if l.cache == nil { l.cache = map[uuid.UUID]*models.Performer{} } l.cache[key] = value } // keyIndex will return the location of the key in the batch, if its not found // it will add the key to the batch func (b *performerLoaderBatch) keyIndex(l *PerformerLoader, key uuid.UUID) int { for i, existingKey := range b.keys { if key == existingKey { return i } } pos := len(b.keys) b.keys = append(b.keys, key) if pos == 0 { go b.startTimer(l) } if l.maxBatch != 0 && pos >= l.maxBatch-1 { if !b.closing { b.closing = true l.batch = nil go b.end(l) } } return pos } func (b *performerLoaderBatch) startTimer(l *PerformerLoader) { time.Sleep(l.wait) l.mu.Lock() // we must have hit a batch limit and are already finalizing this batch if b.closing { l.mu.Unlock() return } l.batch = nil l.mu.Unlock() b.end(l) } func (b *performerLoaderBatch) end(l *PerformerLoader) { b.data, b.error = l.fetch(b.keys) close(b.done) } ================================================ FILE: internal/dataloader/sceneappearancesloader_gen.go ================================================ // Code generated by github.com/vektah/dataloaden, DO NOT EDIT. package dataloader import ( "sync" "time" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" ) // SceneAppearancesLoaderConfig captures the config to create a new SceneAppearancesLoader type SceneAppearancesLoaderConfig struct { // Fetch is a method that provides the data for the loader Fetch func(keys []uuid.UUID) ([][]models.PerformerScene, []error) // Wait is how long wait before sending a batch Wait time.Duration // MaxBatch will limit the maximum number of keys to send in one batch, 0 = not limit MaxBatch int } // NewSceneAppearancesLoader creates a new SceneAppearancesLoader given a fetch, wait, and maxBatch func NewSceneAppearancesLoader(config SceneAppearancesLoaderConfig) *SceneAppearancesLoader { return &SceneAppearancesLoader{ fetch: config.Fetch, wait: config.Wait, maxBatch: config.MaxBatch, } } // SceneAppearancesLoader batches and caches requests type SceneAppearancesLoader struct { // this method provides the data for the loader fetch func(keys []uuid.UUID) ([][]models.PerformerScene, []error) // how long to done before sending a batch wait time.Duration // this will limit the maximum number of keys to send in one batch, 0 = no limit maxBatch int // INTERNAL // lazily created cache cache map[uuid.UUID][]models.PerformerScene // the current batch. keys will continue to be collected until timeout is hit, // then everything will be sent to the fetch method and out to the listeners batch *sceneAppearancesLoaderBatch // mutex to prevent races mu sync.Mutex } type sceneAppearancesLoaderBatch struct { keys []uuid.UUID data [][]models.PerformerScene error []error closing bool done chan struct{} } // Load a PerformerScene by key, batching and caching will be applied automatically func (l *SceneAppearancesLoader) Load(key uuid.UUID) ([]models.PerformerScene, error) { return l.LoadThunk(key)() } // LoadThunk returns a function that when called will block waiting for a PerformerScene. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *SceneAppearancesLoader) LoadThunk(key uuid.UUID) func() ([]models.PerformerScene, error) { l.mu.Lock() if it, ok := l.cache[key]; ok { l.mu.Unlock() return func() ([]models.PerformerScene, error) { return it, nil } } if l.batch == nil { l.batch = &sceneAppearancesLoaderBatch{done: make(chan struct{})} } batch := l.batch pos := batch.keyIndex(l, key) l.mu.Unlock() return func() ([]models.PerformerScene, error) { <-batch.done var data []models.PerformerScene if pos < len(batch.data) { data = batch.data[pos] } var err error // its convenient to be able to return a single error for everything if len(batch.error) == 1 { err = batch.error[0] } else if batch.error != nil { err = batch.error[pos] } if err == nil { l.mu.Lock() l.unsafeSet(key, data) l.mu.Unlock() } return data, err } } // LoadAll fetches many keys at once. It will be broken into appropriate sized // sub batches depending on how the loader is configured func (l *SceneAppearancesLoader) LoadAll(keys []uuid.UUID) ([][]models.PerformerScene, []error) { results := make([]func() ([]models.PerformerScene, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } performerScenes := make([][]models.PerformerScene, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { performerScenes[i], errors[i] = thunk() } return performerScenes, errors } // LoadAllThunk returns a function that when called will block waiting for a PerformerScenes. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *SceneAppearancesLoader) LoadAllThunk(keys []uuid.UUID) func() ([][]models.PerformerScene, []error) { results := make([]func() ([]models.PerformerScene, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } return func() ([][]models.PerformerScene, []error) { performerScenes := make([][]models.PerformerScene, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { performerScenes[i], errors[i] = thunk() } return performerScenes, errors } } // Prime the cache with the provided key and value. If the key already exists, no change is made // and false is returned. // (To forcefully prime the cache, clear the key first with loader.clear(key).prime(key, value).) func (l *SceneAppearancesLoader) Prime(key uuid.UUID, value []models.PerformerScene) bool { l.mu.Lock() var found bool if _, found = l.cache[key]; !found { // make a copy when writing to the cache, its easy to pass a pointer in from a loop var // and end up with the whole cache pointing to the same value. cpy := make([]models.PerformerScene, len(value)) copy(cpy, value) l.unsafeSet(key, cpy) } l.mu.Unlock() return !found } // Clear the value at key from the cache, if it exists func (l *SceneAppearancesLoader) Clear(key uuid.UUID) { l.mu.Lock() delete(l.cache, key) l.mu.Unlock() } func (l *SceneAppearancesLoader) unsafeSet(key uuid.UUID, value []models.PerformerScene) { if l.cache == nil { l.cache = map[uuid.UUID][]models.PerformerScene{} } l.cache[key] = value } // keyIndex will return the location of the key in the batch, if its not found // it will add the key to the batch func (b *sceneAppearancesLoaderBatch) keyIndex(l *SceneAppearancesLoader, key uuid.UUID) int { for i, existingKey := range b.keys { if key == existingKey { return i } } pos := len(b.keys) b.keys = append(b.keys, key) if pos == 0 { go b.startTimer(l) } if l.maxBatch != 0 && pos >= l.maxBatch-1 { if !b.closing { b.closing = true l.batch = nil go b.end(l) } } return pos } func (b *sceneAppearancesLoaderBatch) startTimer(l *SceneAppearancesLoader) { time.Sleep(l.wait) l.mu.Lock() // we must have hit a batch limit and are already finalizing this batch if b.closing { l.mu.Unlock() return } l.batch = nil l.mu.Unlock() b.end(l) } func (b *sceneAppearancesLoaderBatch) end(l *SceneAppearancesLoader) { b.data, b.error = l.fetch(b.keys) close(b.done) } ================================================ FILE: internal/dataloader/sceneloader_gen.go ================================================ // Code generated by github.com/vektah/dataloaden, DO NOT EDIT. package dataloader import ( "sync" "time" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" ) // SceneLoaderConfig captures the config to create a new SceneLoader type SceneLoaderConfig struct { // Fetch is a method that provides the data for the loader Fetch func(keys []uuid.UUID) ([]*models.Scene, []error) // Wait is how long wait before sending a batch Wait time.Duration // MaxBatch will limit the maximum number of keys to send in one batch, 0 = not limit MaxBatch int } // NewSceneLoader creates a new SceneLoader given a fetch, wait, and maxBatch func NewSceneLoader(config SceneLoaderConfig) *SceneLoader { return &SceneLoader{ fetch: config.Fetch, wait: config.Wait, maxBatch: config.MaxBatch, } } // SceneLoader batches and caches requests type SceneLoader struct { // this method provides the data for the loader fetch func(keys []uuid.UUID) ([]*models.Scene, []error) // how long to done before sending a batch wait time.Duration // this will limit the maximum number of keys to send in one batch, 0 = no limit maxBatch int // INTERNAL // lazily created cache cache map[uuid.UUID]*models.Scene // the current batch. keys will continue to be collected until timeout is hit, // then everything will be sent to the fetch method and out to the listeners batch *sceneLoaderBatch // mutex to prevent races mu sync.Mutex } type sceneLoaderBatch struct { keys []uuid.UUID data []*models.Scene error []error closing bool done chan struct{} } // Load a Scene by key, batching and caching will be applied automatically func (l *SceneLoader) Load(key uuid.UUID) (*models.Scene, error) { return l.LoadThunk(key)() } // LoadThunk returns a function that when called will block waiting for a Scene. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *SceneLoader) LoadThunk(key uuid.UUID) func() (*models.Scene, error) { l.mu.Lock() if it, ok := l.cache[key]; ok { l.mu.Unlock() return func() (*models.Scene, error) { return it, nil } } if l.batch == nil { l.batch = &sceneLoaderBatch{done: make(chan struct{})} } batch := l.batch pos := batch.keyIndex(l, key) l.mu.Unlock() return func() (*models.Scene, error) { <-batch.done var data *models.Scene if pos < len(batch.data) { data = batch.data[pos] } var err error // its convenient to be able to return a single error for everything if len(batch.error) == 1 { err = batch.error[0] } else if batch.error != nil { err = batch.error[pos] } if err == nil { l.mu.Lock() l.unsafeSet(key, data) l.mu.Unlock() } return data, err } } // LoadAll fetches many keys at once. It will be broken into appropriate sized // sub batches depending on how the loader is configured func (l *SceneLoader) LoadAll(keys []uuid.UUID) ([]*models.Scene, []error) { results := make([]func() (*models.Scene, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } scenes := make([]*models.Scene, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { scenes[i], errors[i] = thunk() } return scenes, errors } // LoadAllThunk returns a function that when called will block waiting for a Scenes. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *SceneLoader) LoadAllThunk(keys []uuid.UUID) func() ([]*models.Scene, []error) { results := make([]func() (*models.Scene, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } return func() ([]*models.Scene, []error) { scenes := make([]*models.Scene, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { scenes[i], errors[i] = thunk() } return scenes, errors } } // Prime the cache with the provided key and value. If the key already exists, no change is made // and false is returned. // (To forcefully prime the cache, clear the key first with loader.clear(key).prime(key, value).) func (l *SceneLoader) Prime(key uuid.UUID, value *models.Scene) bool { l.mu.Lock() var found bool if _, found = l.cache[key]; !found { // make a copy when writing to the cache, its easy to pass a pointer in from a loop var // and end up with the whole cache pointing to the same value. cpy := *value l.unsafeSet(key, &cpy) } l.mu.Unlock() return !found } // Clear the value at key from the cache, if it exists func (l *SceneLoader) Clear(key uuid.UUID) { l.mu.Lock() delete(l.cache, key) l.mu.Unlock() } func (l *SceneLoader) unsafeSet(key uuid.UUID, value *models.Scene) { if l.cache == nil { l.cache = map[uuid.UUID]*models.Scene{} } l.cache[key] = value } // keyIndex will return the location of the key in the batch, if its not found // it will add the key to the batch func (b *sceneLoaderBatch) keyIndex(l *SceneLoader, key uuid.UUID) int { for i, existingKey := range b.keys { if key == existingKey { return i } } pos := len(b.keys) b.keys = append(b.keys, key) if pos == 0 { go b.startTimer(l) } if l.maxBatch != 0 && pos >= l.maxBatch-1 { if !b.closing { b.closing = true l.batch = nil go b.end(l) } } return pos } func (b *sceneLoaderBatch) startTimer(l *SceneLoader) { time.Sleep(l.wait) l.mu.Lock() // we must have hit a batch limit and are already finalizing this batch if b.closing { l.mu.Unlock() return } l.batch = nil l.mu.Unlock() b.end(l) } func (b *sceneLoaderBatch) end(l *SceneLoader) { b.data, b.error = l.fetch(b.keys) close(b.done) } ================================================ FILE: internal/dataloader/siteloader_gen.go ================================================ // Code generated by github.com/vektah/dataloaden, DO NOT EDIT. package dataloader import ( "sync" "time" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" ) // SiteLoaderConfig captures the config to create a new SiteLoader type SiteLoaderConfig struct { // Fetch is a method that provides the data for the loader Fetch func(keys []uuid.UUID) ([]*models.Site, []error) // Wait is how long wait before sending a batch Wait time.Duration // MaxBatch will limit the maximum number of keys to send in one batch, 0 = not limit MaxBatch int } // NewSiteLoader creates a new SiteLoader given a fetch, wait, and maxBatch func NewSiteLoader(config SiteLoaderConfig) *SiteLoader { return &SiteLoader{ fetch: config.Fetch, wait: config.Wait, maxBatch: config.MaxBatch, } } // SiteLoader batches and caches requests type SiteLoader struct { // this method provides the data for the loader fetch func(keys []uuid.UUID) ([]*models.Site, []error) // how long to done before sending a batch wait time.Duration // this will limit the maximum number of keys to send in one batch, 0 = no limit maxBatch int // INTERNAL // lazily created cache cache map[uuid.UUID]*models.Site // the current batch. keys will continue to be collected until timeout is hit, // then everything will be sent to the fetch method and out to the listeners batch *siteLoaderBatch // mutex to prevent races mu sync.Mutex } type siteLoaderBatch struct { keys []uuid.UUID data []*models.Site error []error closing bool done chan struct{} } // Load a Site by key, batching and caching will be applied automatically func (l *SiteLoader) Load(key uuid.UUID) (*models.Site, error) { return l.LoadThunk(key)() } // LoadThunk returns a function that when called will block waiting for a Site. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *SiteLoader) LoadThunk(key uuid.UUID) func() (*models.Site, error) { l.mu.Lock() if it, ok := l.cache[key]; ok { l.mu.Unlock() return func() (*models.Site, error) { return it, nil } } if l.batch == nil { l.batch = &siteLoaderBatch{done: make(chan struct{})} } batch := l.batch pos := batch.keyIndex(l, key) l.mu.Unlock() return func() (*models.Site, error) { <-batch.done var data *models.Site if pos < len(batch.data) { data = batch.data[pos] } var err error // its convenient to be able to return a single error for everything if len(batch.error) == 1 { err = batch.error[0] } else if batch.error != nil { err = batch.error[pos] } if err == nil { l.mu.Lock() l.unsafeSet(key, data) l.mu.Unlock() } return data, err } } // LoadAll fetches many keys at once. It will be broken into appropriate sized // sub batches depending on how the loader is configured func (l *SiteLoader) LoadAll(keys []uuid.UUID) ([]*models.Site, []error) { results := make([]func() (*models.Site, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } sites := make([]*models.Site, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { sites[i], errors[i] = thunk() } return sites, errors } // LoadAllThunk returns a function that when called will block waiting for a Sites. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *SiteLoader) LoadAllThunk(keys []uuid.UUID) func() ([]*models.Site, []error) { results := make([]func() (*models.Site, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } return func() ([]*models.Site, []error) { sites := make([]*models.Site, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { sites[i], errors[i] = thunk() } return sites, errors } } // Prime the cache with the provided key and value. If the key already exists, no change is made // and false is returned. // (To forcefully prime the cache, clear the key first with loader.clear(key).prime(key, value).) func (l *SiteLoader) Prime(key uuid.UUID, value *models.Site) bool { l.mu.Lock() var found bool if _, found = l.cache[key]; !found { // make a copy when writing to the cache, its easy to pass a pointer in from a loop var // and end up with the whole cache pointing to the same value. cpy := *value l.unsafeSet(key, &cpy) } l.mu.Unlock() return !found } // Clear the value at key from the cache, if it exists func (l *SiteLoader) Clear(key uuid.UUID) { l.mu.Lock() delete(l.cache, key) l.mu.Unlock() } func (l *SiteLoader) unsafeSet(key uuid.UUID, value *models.Site) { if l.cache == nil { l.cache = map[uuid.UUID]*models.Site{} } l.cache[key] = value } // keyIndex will return the location of the key in the batch, if its not found // it will add the key to the batch func (b *siteLoaderBatch) keyIndex(l *SiteLoader, key uuid.UUID) int { for i, existingKey := range b.keys { if key == existingKey { return i } } pos := len(b.keys) b.keys = append(b.keys, key) if pos == 0 { go b.startTimer(l) } if l.maxBatch != 0 && pos >= l.maxBatch-1 { if !b.closing { b.closing = true l.batch = nil go b.end(l) } } return pos } func (b *siteLoaderBatch) startTimer(l *SiteLoader) { time.Sleep(l.wait) l.mu.Lock() // we must have hit a batch limit and are already finalizing this batch if b.closing { l.mu.Unlock() return } l.batch = nil l.mu.Unlock() b.end(l) } func (b *siteLoaderBatch) end(l *SiteLoader) { b.data, b.error = l.fetch(b.keys) close(b.done) } ================================================ FILE: internal/dataloader/stringsloader_gen.go ================================================ // Code generated by github.com/vektah/dataloaden, DO NOT EDIT. package dataloader import ( "sync" "time" "github.com/gofrs/uuid" ) // StringsLoaderConfig captures the config to create a new StringsLoader type StringsLoaderConfig struct { // Fetch is a method that provides the data for the loader Fetch func(keys []uuid.UUID) ([][]string, []error) // Wait is how long wait before sending a batch Wait time.Duration // MaxBatch will limit the maximum number of keys to send in one batch, 0 = not limit MaxBatch int } // NewStringsLoader creates a new StringsLoader given a fetch, wait, and maxBatch func NewStringsLoader(config StringsLoaderConfig) *StringsLoader { return &StringsLoader{ fetch: config.Fetch, wait: config.Wait, maxBatch: config.MaxBatch, } } // StringsLoader batches and caches requests type StringsLoader struct { // this method provides the data for the loader fetch func(keys []uuid.UUID) ([][]string, []error) // how long to done before sending a batch wait time.Duration // this will limit the maximum number of keys to send in one batch, 0 = no limit maxBatch int // INTERNAL // lazily created cache cache map[uuid.UUID][]string // the current batch. keys will continue to be collected until timeout is hit, // then everything will be sent to the fetch method and out to the listeners batch *stringsLoaderBatch // mutex to prevent races mu sync.Mutex } type stringsLoaderBatch struct { keys []uuid.UUID data [][]string error []error closing bool done chan struct{} } // Load a string by key, batching and caching will be applied automatically func (l *StringsLoader) Load(key uuid.UUID) ([]string, error) { return l.LoadThunk(key)() } // LoadThunk returns a function that when called will block waiting for a string. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *StringsLoader) LoadThunk(key uuid.UUID) func() ([]string, error) { l.mu.Lock() if it, ok := l.cache[key]; ok { l.mu.Unlock() return func() ([]string, error) { return it, nil } } if l.batch == nil { l.batch = &stringsLoaderBatch{done: make(chan struct{})} } batch := l.batch pos := batch.keyIndex(l, key) l.mu.Unlock() return func() ([]string, error) { <-batch.done var data []string if pos < len(batch.data) { data = batch.data[pos] } var err error // its convenient to be able to return a single error for everything if len(batch.error) == 1 { err = batch.error[0] } else if batch.error != nil { err = batch.error[pos] } if err == nil { l.mu.Lock() l.unsafeSet(key, data) l.mu.Unlock() } return data, err } } // LoadAll fetches many keys at once. It will be broken into appropriate sized // sub batches depending on how the loader is configured func (l *StringsLoader) LoadAll(keys []uuid.UUID) ([][]string, []error) { results := make([]func() ([]string, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } strings := make([][]string, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { strings[i], errors[i] = thunk() } return strings, errors } // LoadAllThunk returns a function that when called will block waiting for a strings. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *StringsLoader) LoadAllThunk(keys []uuid.UUID) func() ([][]string, []error) { results := make([]func() ([]string, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } return func() ([][]string, []error) { strings := make([][]string, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { strings[i], errors[i] = thunk() } return strings, errors } } // Prime the cache with the provided key and value. If the key already exists, no change is made // and false is returned. // (To forcefully prime the cache, clear the key first with loader.clear(key).prime(key, value).) func (l *StringsLoader) Prime(key uuid.UUID, value []string) bool { l.mu.Lock() var found bool if _, found = l.cache[key]; !found { // make a copy when writing to the cache, its easy to pass a pointer in from a loop var // and end up with the whole cache pointing to the same value. cpy := make([]string, len(value)) copy(cpy, value) l.unsafeSet(key, cpy) } l.mu.Unlock() return !found } // Clear the value at key from the cache, if it exists func (l *StringsLoader) Clear(key uuid.UUID) { l.mu.Lock() delete(l.cache, key) l.mu.Unlock() } func (l *StringsLoader) unsafeSet(key uuid.UUID, value []string) { if l.cache == nil { l.cache = map[uuid.UUID][]string{} } l.cache[key] = value } // keyIndex will return the location of the key in the batch, if its not found // it will add the key to the batch func (b *stringsLoaderBatch) keyIndex(l *StringsLoader, key uuid.UUID) int { for i, existingKey := range b.keys { if key == existingKey { return i } } pos := len(b.keys) b.keys = append(b.keys, key) if pos == 0 { go b.startTimer(l) } if l.maxBatch != 0 && pos >= l.maxBatch-1 { if !b.closing { b.closing = true l.batch = nil go b.end(l) } } return pos } func (b *stringsLoaderBatch) startTimer(l *StringsLoader) { time.Sleep(l.wait) l.mu.Lock() // we must have hit a batch limit and are already finalizing this batch if b.closing { l.mu.Unlock() return } l.batch = nil l.mu.Unlock() b.end(l) } func (b *stringsLoaderBatch) end(l *StringsLoader) { b.data, b.error = l.fetch(b.keys) close(b.done) } ================================================ FILE: internal/dataloader/studioloader_gen.go ================================================ // Code generated by github.com/vektah/dataloaden, DO NOT EDIT. package dataloader import ( "sync" "time" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" ) // StudioLoaderConfig captures the config to create a new StudioLoader type StudioLoaderConfig struct { // Fetch is a method that provides the data for the loader Fetch func(keys []uuid.UUID) ([]*models.Studio, []error) // Wait is how long wait before sending a batch Wait time.Duration // MaxBatch will limit the maximum number of keys to send in one batch, 0 = not limit MaxBatch int } // NewStudioLoader creates a new StudioLoader given a fetch, wait, and maxBatch func NewStudioLoader(config StudioLoaderConfig) *StudioLoader { return &StudioLoader{ fetch: config.Fetch, wait: config.Wait, maxBatch: config.MaxBatch, } } // StudioLoader batches and caches requests type StudioLoader struct { // this method provides the data for the loader fetch func(keys []uuid.UUID) ([]*models.Studio, []error) // how long to done before sending a batch wait time.Duration // this will limit the maximum number of keys to send in one batch, 0 = no limit maxBatch int // INTERNAL // lazily created cache cache map[uuid.UUID]*models.Studio // the current batch. keys will continue to be collected until timeout is hit, // then everything will be sent to the fetch method and out to the listeners batch *studioLoaderBatch // mutex to prevent races mu sync.Mutex } type studioLoaderBatch struct { keys []uuid.UUID data []*models.Studio error []error closing bool done chan struct{} } // Load a Studio by key, batching and caching will be applied automatically func (l *StudioLoader) Load(key uuid.UUID) (*models.Studio, error) { return l.LoadThunk(key)() } // LoadThunk returns a function that when called will block waiting for a Studio. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *StudioLoader) LoadThunk(key uuid.UUID) func() (*models.Studio, error) { l.mu.Lock() if it, ok := l.cache[key]; ok { l.mu.Unlock() return func() (*models.Studio, error) { return it, nil } } if l.batch == nil { l.batch = &studioLoaderBatch{done: make(chan struct{})} } batch := l.batch pos := batch.keyIndex(l, key) l.mu.Unlock() return func() (*models.Studio, error) { <-batch.done var data *models.Studio if pos < len(batch.data) { data = batch.data[pos] } var err error // its convenient to be able to return a single error for everything if len(batch.error) == 1 { err = batch.error[0] } else if batch.error != nil { err = batch.error[pos] } if err == nil { l.mu.Lock() l.unsafeSet(key, data) l.mu.Unlock() } return data, err } } // LoadAll fetches many keys at once. It will be broken into appropriate sized // sub batches depending on how the loader is configured func (l *StudioLoader) LoadAll(keys []uuid.UUID) ([]*models.Studio, []error) { results := make([]func() (*models.Studio, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } studios := make([]*models.Studio, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { studios[i], errors[i] = thunk() } return studios, errors } // LoadAllThunk returns a function that when called will block waiting for a Studios. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *StudioLoader) LoadAllThunk(keys []uuid.UUID) func() ([]*models.Studio, []error) { results := make([]func() (*models.Studio, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } return func() ([]*models.Studio, []error) { studios := make([]*models.Studio, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { studios[i], errors[i] = thunk() } return studios, errors } } // Prime the cache with the provided key and value. If the key already exists, no change is made // and false is returned. // (To forcefully prime the cache, clear the key first with loader.clear(key).prime(key, value).) func (l *StudioLoader) Prime(key uuid.UUID, value *models.Studio) bool { l.mu.Lock() var found bool if _, found = l.cache[key]; !found { // make a copy when writing to the cache, its easy to pass a pointer in from a loop var // and end up with the whole cache pointing to the same value. cpy := *value l.unsafeSet(key, &cpy) } l.mu.Unlock() return !found } // Clear the value at key from the cache, if it exists func (l *StudioLoader) Clear(key uuid.UUID) { l.mu.Lock() delete(l.cache, key) l.mu.Unlock() } func (l *StudioLoader) unsafeSet(key uuid.UUID, value *models.Studio) { if l.cache == nil { l.cache = map[uuid.UUID]*models.Studio{} } l.cache[key] = value } // keyIndex will return the location of the key in the batch, if its not found // it will add the key to the batch func (b *studioLoaderBatch) keyIndex(l *StudioLoader, key uuid.UUID) int { for i, existingKey := range b.keys { if key == existingKey { return i } } pos := len(b.keys) b.keys = append(b.keys, key) if pos == 0 { go b.startTimer(l) } if l.maxBatch != 0 && pos >= l.maxBatch-1 { if !b.closing { b.closing = true l.batch = nil go b.end(l) } } return pos } func (b *studioLoaderBatch) startTimer(l *StudioLoader) { time.Sleep(l.wait) l.mu.Lock() // we must have hit a batch limit and are already finalizing this batch if b.closing { l.mu.Unlock() return } l.batch = nil l.mu.Unlock() b.end(l) } func (b *studioLoaderBatch) end(l *StudioLoader) { b.data, b.error = l.fetch(b.keys) close(b.done) } ================================================ FILE: internal/dataloader/submittedfingerprintsloader_gen.go ================================================ // Code generated by github.com/vektah/dataloaden, DO NOT EDIT. package dataloader import ( "sync" "time" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" ) // SubmittedFingerprintsLoaderConfig captures the config to create a new SubmittedFingerprintsLoader type SubmittedFingerprintsLoaderConfig struct { // Fetch is a method that provides the data for the loader Fetch func(keys []uuid.UUID) ([][]models.Fingerprint, []error) // Wait is how long wait before sending a batch Wait time.Duration // MaxBatch will limit the maximum number of keys to send in one batch, 0 = not limit MaxBatch int } // NewSubmittedFingerprintsLoader creates a new SubmittedFingerprintsLoader given a fetch, wait, and maxBatch func NewSubmittedFingerprintsLoader(config SubmittedFingerprintsLoaderConfig) *SubmittedFingerprintsLoader { return &SubmittedFingerprintsLoader{ fetch: config.Fetch, wait: config.Wait, maxBatch: config.MaxBatch, } } // SubmittedFingerprintsLoader batches and caches requests type SubmittedFingerprintsLoader struct { // this method provides the data for the loader fetch func(keys []uuid.UUID) ([][]models.Fingerprint, []error) // how long to done before sending a batch wait time.Duration // this will limit the maximum number of keys to send in one batch, 0 = no limit maxBatch int // INTERNAL // lazily created cache cache map[uuid.UUID][]models.Fingerprint // the current batch. keys will continue to be collected until timeout is hit, // then everything will be sent to the fetch method and out to the listeners batch *submittedFingerprintsLoaderBatch // mutex to prevent races mu sync.Mutex } type submittedFingerprintsLoaderBatch struct { keys []uuid.UUID data [][]models.Fingerprint error []error closing bool done chan struct{} } // Load a Fingerprint by key, batching and caching will be applied automatically func (l *SubmittedFingerprintsLoader) Load(key uuid.UUID) ([]models.Fingerprint, error) { return l.LoadThunk(key)() } // LoadThunk returns a function that when called will block waiting for a Fingerprint. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *SubmittedFingerprintsLoader) LoadThunk(key uuid.UUID) func() ([]models.Fingerprint, error) { l.mu.Lock() if it, ok := l.cache[key]; ok { l.mu.Unlock() return func() ([]models.Fingerprint, error) { return it, nil } } if l.batch == nil { l.batch = &submittedFingerprintsLoaderBatch{done: make(chan struct{})} } batch := l.batch pos := batch.keyIndex(l, key) l.mu.Unlock() return func() ([]models.Fingerprint, error) { <-batch.done var data []models.Fingerprint if pos < len(batch.data) { data = batch.data[pos] } var err error // its convenient to be able to return a single error for everything if len(batch.error) == 1 { err = batch.error[0] } else if batch.error != nil { err = batch.error[pos] } if err == nil { l.mu.Lock() l.unsafeSet(key, data) l.mu.Unlock() } return data, err } } // LoadAll fetches many keys at once. It will be broken into appropriate sized // sub batches depending on how the loader is configured func (l *SubmittedFingerprintsLoader) LoadAll(keys []uuid.UUID) ([][]models.Fingerprint, []error) { results := make([]func() ([]models.Fingerprint, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } fingerprints := make([][]models.Fingerprint, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { fingerprints[i], errors[i] = thunk() } return fingerprints, errors } // LoadAllThunk returns a function that when called will block waiting for a Fingerprints. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *SubmittedFingerprintsLoader) LoadAllThunk(keys []uuid.UUID) func() ([][]models.Fingerprint, []error) { results := make([]func() ([]models.Fingerprint, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } return func() ([][]models.Fingerprint, []error) { fingerprints := make([][]models.Fingerprint, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { fingerprints[i], errors[i] = thunk() } return fingerprints, errors } } // Prime the cache with the provided key and value. If the key already exists, no change is made // and false is returned. // (To forcefully prime the cache, clear the key first with loader.clear(key).prime(key, value).) func (l *SubmittedFingerprintsLoader) Prime(key uuid.UUID, value []models.Fingerprint) bool { l.mu.Lock() var found bool if _, found = l.cache[key]; !found { // make a copy when writing to the cache, its easy to pass a pointer in from a loop var // and end up with the whole cache pointing to the same value. cpy := make([]models.Fingerprint, len(value)) copy(cpy, value) l.unsafeSet(key, cpy) } l.mu.Unlock() return !found } // Clear the value at key from the cache, if it exists func (l *SubmittedFingerprintsLoader) Clear(key uuid.UUID) { l.mu.Lock() delete(l.cache, key) l.mu.Unlock() } func (l *SubmittedFingerprintsLoader) unsafeSet(key uuid.UUID, value []models.Fingerprint) { if l.cache == nil { l.cache = map[uuid.UUID][]models.Fingerprint{} } l.cache[key] = value } // keyIndex will return the location of the key in the batch, if its not found // it will add the key to the batch func (b *submittedFingerprintsLoaderBatch) keyIndex(l *SubmittedFingerprintsLoader, key uuid.UUID) int { for i, existingKey := range b.keys { if key == existingKey { return i } } pos := len(b.keys) b.keys = append(b.keys, key) if pos == 0 { go b.startTimer(l) } if l.maxBatch != 0 && pos >= l.maxBatch-1 { if !b.closing { b.closing = true l.batch = nil go b.end(l) } } return pos } func (b *submittedFingerprintsLoaderBatch) startTimer(l *SubmittedFingerprintsLoader) { time.Sleep(l.wait) l.mu.Lock() // we must have hit a batch limit and are already finalizing this batch if b.closing { l.mu.Unlock() return } l.batch = nil l.mu.Unlock() b.end(l) } func (b *submittedFingerprintsLoaderBatch) end(l *SubmittedFingerprintsLoader) { b.data, b.error = l.fetch(b.keys) close(b.done) } ================================================ FILE: internal/dataloader/tagcategoryloader_gen.go ================================================ // Code generated by github.com/vektah/dataloaden, DO NOT EDIT. package dataloader import ( "sync" "time" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" ) // TagCategoryLoaderConfig captures the config to create a new TagCategoryLoader type TagCategoryLoaderConfig struct { // Fetch is a method that provides the data for the loader Fetch func(keys []uuid.UUID) ([]*models.TagCategory, []error) // Wait is how long wait before sending a batch Wait time.Duration // MaxBatch will limit the maximum number of keys to send in one batch, 0 = not limit MaxBatch int } // NewTagCategoryLoader creates a new TagCategoryLoader given a fetch, wait, and maxBatch func NewTagCategoryLoader(config TagCategoryLoaderConfig) *TagCategoryLoader { return &TagCategoryLoader{ fetch: config.Fetch, wait: config.Wait, maxBatch: config.MaxBatch, } } // TagCategoryLoader batches and caches requests type TagCategoryLoader struct { // this method provides the data for the loader fetch func(keys []uuid.UUID) ([]*models.TagCategory, []error) // how long to done before sending a batch wait time.Duration // this will limit the maximum number of keys to send in one batch, 0 = no limit maxBatch int // INTERNAL // lazily created cache cache map[uuid.UUID]*models.TagCategory // the current batch. keys will continue to be collected until timeout is hit, // then everything will be sent to the fetch method and out to the listeners batch *tagCategoryLoaderBatch // mutex to prevent races mu sync.Mutex } type tagCategoryLoaderBatch struct { keys []uuid.UUID data []*models.TagCategory error []error closing bool done chan struct{} } // Load a TagCategory by key, batching and caching will be applied automatically func (l *TagCategoryLoader) Load(key uuid.UUID) (*models.TagCategory, error) { return l.LoadThunk(key)() } // LoadThunk returns a function that when called will block waiting for a TagCategory. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *TagCategoryLoader) LoadThunk(key uuid.UUID) func() (*models.TagCategory, error) { l.mu.Lock() if it, ok := l.cache[key]; ok { l.mu.Unlock() return func() (*models.TagCategory, error) { return it, nil } } if l.batch == nil { l.batch = &tagCategoryLoaderBatch{done: make(chan struct{})} } batch := l.batch pos := batch.keyIndex(l, key) l.mu.Unlock() return func() (*models.TagCategory, error) { <-batch.done var data *models.TagCategory if pos < len(batch.data) { data = batch.data[pos] } var err error // its convenient to be able to return a single error for everything if len(batch.error) == 1 { err = batch.error[0] } else if batch.error != nil { err = batch.error[pos] } if err == nil { l.mu.Lock() l.unsafeSet(key, data) l.mu.Unlock() } return data, err } } // LoadAll fetches many keys at once. It will be broken into appropriate sized // sub batches depending on how the loader is configured func (l *TagCategoryLoader) LoadAll(keys []uuid.UUID) ([]*models.TagCategory, []error) { results := make([]func() (*models.TagCategory, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } tagCategorys := make([]*models.TagCategory, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { tagCategorys[i], errors[i] = thunk() } return tagCategorys, errors } // LoadAllThunk returns a function that when called will block waiting for a TagCategorys. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *TagCategoryLoader) LoadAllThunk(keys []uuid.UUID) func() ([]*models.TagCategory, []error) { results := make([]func() (*models.TagCategory, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } return func() ([]*models.TagCategory, []error) { tagCategorys := make([]*models.TagCategory, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { tagCategorys[i], errors[i] = thunk() } return tagCategorys, errors } } // Prime the cache with the provided key and value. If the key already exists, no change is made // and false is returned. // (To forcefully prime the cache, clear the key first with loader.clear(key).prime(key, value).) func (l *TagCategoryLoader) Prime(key uuid.UUID, value *models.TagCategory) bool { l.mu.Lock() var found bool if _, found = l.cache[key]; !found { // make a copy when writing to the cache, its easy to pass a pointer in from a loop var // and end up with the whole cache pointing to the same value. cpy := *value l.unsafeSet(key, &cpy) } l.mu.Unlock() return !found } // Clear the value at key from the cache, if it exists func (l *TagCategoryLoader) Clear(key uuid.UUID) { l.mu.Lock() delete(l.cache, key) l.mu.Unlock() } func (l *TagCategoryLoader) unsafeSet(key uuid.UUID, value *models.TagCategory) { if l.cache == nil { l.cache = map[uuid.UUID]*models.TagCategory{} } l.cache[key] = value } // keyIndex will return the location of the key in the batch, if its not found // it will add the key to the batch func (b *tagCategoryLoaderBatch) keyIndex(l *TagCategoryLoader, key uuid.UUID) int { for i, existingKey := range b.keys { if key == existingKey { return i } } pos := len(b.keys) b.keys = append(b.keys, key) if pos == 0 { go b.startTimer(l) } if l.maxBatch != 0 && pos >= l.maxBatch-1 { if !b.closing { b.closing = true l.batch = nil go b.end(l) } } return pos } func (b *tagCategoryLoaderBatch) startTimer(l *TagCategoryLoader) { time.Sleep(l.wait) l.mu.Lock() // we must have hit a batch limit and are already finalizing this batch if b.closing { l.mu.Unlock() return } l.batch = nil l.mu.Unlock() b.end(l) } func (b *tagCategoryLoaderBatch) end(l *TagCategoryLoader) { b.data, b.error = l.fetch(b.keys) close(b.done) } ================================================ FILE: internal/dataloader/tagloader_gen.go ================================================ // Code generated by github.com/vektah/dataloaden, DO NOT EDIT. package dataloader import ( "sync" "time" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" ) // TagLoaderConfig captures the config to create a new TagLoader type TagLoaderConfig struct { // Fetch is a method that provides the data for the loader Fetch func(keys []uuid.UUID) ([]*models.Tag, []error) // Wait is how long wait before sending a batch Wait time.Duration // MaxBatch will limit the maximum number of keys to send in one batch, 0 = not limit MaxBatch int } // NewTagLoader creates a new TagLoader given a fetch, wait, and maxBatch func NewTagLoader(config TagLoaderConfig) *TagLoader { return &TagLoader{ fetch: config.Fetch, wait: config.Wait, maxBatch: config.MaxBatch, } } // TagLoader batches and caches requests type TagLoader struct { // this method provides the data for the loader fetch func(keys []uuid.UUID) ([]*models.Tag, []error) // how long to done before sending a batch wait time.Duration // this will limit the maximum number of keys to send in one batch, 0 = no limit maxBatch int // INTERNAL // lazily created cache cache map[uuid.UUID]*models.Tag // the current batch. keys will continue to be collected until timeout is hit, // then everything will be sent to the fetch method and out to the listeners batch *tagLoaderBatch // mutex to prevent races mu sync.Mutex } type tagLoaderBatch struct { keys []uuid.UUID data []*models.Tag error []error closing bool done chan struct{} } // Load a Tag by key, batching and caching will be applied automatically func (l *TagLoader) Load(key uuid.UUID) (*models.Tag, error) { return l.LoadThunk(key)() } // LoadThunk returns a function that when called will block waiting for a Tag. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *TagLoader) LoadThunk(key uuid.UUID) func() (*models.Tag, error) { l.mu.Lock() if it, ok := l.cache[key]; ok { l.mu.Unlock() return func() (*models.Tag, error) { return it, nil } } if l.batch == nil { l.batch = &tagLoaderBatch{done: make(chan struct{})} } batch := l.batch pos := batch.keyIndex(l, key) l.mu.Unlock() return func() (*models.Tag, error) { <-batch.done var data *models.Tag if pos < len(batch.data) { data = batch.data[pos] } var err error // its convenient to be able to return a single error for everything if len(batch.error) == 1 { err = batch.error[0] } else if batch.error != nil { err = batch.error[pos] } if err == nil { l.mu.Lock() l.unsafeSet(key, data) l.mu.Unlock() } return data, err } } // LoadAll fetches many keys at once. It will be broken into appropriate sized // sub batches depending on how the loader is configured func (l *TagLoader) LoadAll(keys []uuid.UUID) ([]*models.Tag, []error) { results := make([]func() (*models.Tag, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } tags := make([]*models.Tag, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { tags[i], errors[i] = thunk() } return tags, errors } // LoadAllThunk returns a function that when called will block waiting for a Tags. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *TagLoader) LoadAllThunk(keys []uuid.UUID) func() ([]*models.Tag, []error) { results := make([]func() (*models.Tag, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } return func() ([]*models.Tag, []error) { tags := make([]*models.Tag, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { tags[i], errors[i] = thunk() } return tags, errors } } // Prime the cache with the provided key and value. If the key already exists, no change is made // and false is returned. // (To forcefully prime the cache, clear the key first with loader.clear(key).prime(key, value).) func (l *TagLoader) Prime(key uuid.UUID, value *models.Tag) bool { l.mu.Lock() var found bool if _, found = l.cache[key]; !found { // make a copy when writing to the cache, its easy to pass a pointer in from a loop var // and end up with the whole cache pointing to the same value. cpy := *value l.unsafeSet(key, &cpy) } l.mu.Unlock() return !found } // Clear the value at key from the cache, if it exists func (l *TagLoader) Clear(key uuid.UUID) { l.mu.Lock() delete(l.cache, key) l.mu.Unlock() } func (l *TagLoader) unsafeSet(key uuid.UUID, value *models.Tag) { if l.cache == nil { l.cache = map[uuid.UUID]*models.Tag{} } l.cache[key] = value } // keyIndex will return the location of the key in the batch, if its not found // it will add the key to the batch func (b *tagLoaderBatch) keyIndex(l *TagLoader, key uuid.UUID) int { for i, existingKey := range b.keys { if key == existingKey { return i } } pos := len(b.keys) b.keys = append(b.keys, key) if pos == 0 { go b.startTimer(l) } if l.maxBatch != 0 && pos >= l.maxBatch-1 { if !b.closing { b.closing = true l.batch = nil go b.end(l) } } return pos } func (b *tagLoaderBatch) startTimer(l *TagLoader) { time.Sleep(l.wait) l.mu.Lock() // we must have hit a batch limit and are already finalizing this batch if b.closing { l.mu.Unlock() return } l.batch = nil l.mu.Unlock() b.end(l) } func (b *tagLoaderBatch) end(l *TagLoader) { b.data, b.error = l.fetch(b.keys) close(b.done) } ================================================ FILE: internal/dataloader/urlloader_gen.go ================================================ // Code generated by github.com/vektah/dataloaden, DO NOT EDIT. package dataloader import ( "sync" "time" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" ) // URLLoaderConfig captures the config to create a new URLLoader type URLLoaderConfig struct { // Fetch is a method that provides the data for the loader Fetch func(keys []uuid.UUID) ([][]models.URL, []error) // Wait is how long wait before sending a batch Wait time.Duration // MaxBatch will limit the maximum number of keys to send in one batch, 0 = not limit MaxBatch int } // NewURLLoader creates a new URLLoader given a fetch, wait, and maxBatch func NewURLLoader(config URLLoaderConfig) *URLLoader { return &URLLoader{ fetch: config.Fetch, wait: config.Wait, maxBatch: config.MaxBatch, } } // URLLoader batches and caches requests type URLLoader struct { // this method provides the data for the loader fetch func(keys []uuid.UUID) ([][]models.URL, []error) // how long to done before sending a batch wait time.Duration // this will limit the maximum number of keys to send in one batch, 0 = no limit maxBatch int // INTERNAL // lazily created cache cache map[uuid.UUID][]models.URL // the current batch. keys will continue to be collected until timeout is hit, // then everything will be sent to the fetch method and out to the listeners batch *uRLLoaderBatch // mutex to prevent races mu sync.Mutex } type uRLLoaderBatch struct { keys []uuid.UUID data [][]models.URL error []error closing bool done chan struct{} } // Load a URL by key, batching and caching will be applied automatically func (l *URLLoader) Load(key uuid.UUID) ([]models.URL, error) { return l.LoadThunk(key)() } // LoadThunk returns a function that when called will block waiting for a URL. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *URLLoader) LoadThunk(key uuid.UUID) func() ([]models.URL, error) { l.mu.Lock() if it, ok := l.cache[key]; ok { l.mu.Unlock() return func() ([]models.URL, error) { return it, nil } } if l.batch == nil { l.batch = &uRLLoaderBatch{done: make(chan struct{})} } batch := l.batch pos := batch.keyIndex(l, key) l.mu.Unlock() return func() ([]models.URL, error) { <-batch.done var data []models.URL if pos < len(batch.data) { data = batch.data[pos] } var err error // its convenient to be able to return a single error for everything if len(batch.error) == 1 { err = batch.error[0] } else if batch.error != nil { err = batch.error[pos] } if err == nil { l.mu.Lock() l.unsafeSet(key, data) l.mu.Unlock() } return data, err } } // LoadAll fetches many keys at once. It will be broken into appropriate sized // sub batches depending on how the loader is configured func (l *URLLoader) LoadAll(keys []uuid.UUID) ([][]models.URL, []error) { results := make([]func() ([]models.URL, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } uRLs := make([][]models.URL, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { uRLs[i], errors[i] = thunk() } return uRLs, errors } // LoadAllThunk returns a function that when called will block waiting for a URLs. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *URLLoader) LoadAllThunk(keys []uuid.UUID) func() ([][]models.URL, []error) { results := make([]func() ([]models.URL, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } return func() ([][]models.URL, []error) { uRLs := make([][]models.URL, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { uRLs[i], errors[i] = thunk() } return uRLs, errors } } // Prime the cache with the provided key and value. If the key already exists, no change is made // and false is returned. // (To forcefully prime the cache, clear the key first with loader.clear(key).prime(key, value).) func (l *URLLoader) Prime(key uuid.UUID, value []models.URL) bool { l.mu.Lock() var found bool if _, found = l.cache[key]; !found { // make a copy when writing to the cache, its easy to pass a pointer in from a loop var // and end up with the whole cache pointing to the same value. cpy := make([]models.URL, len(value)) copy(cpy, value) l.unsafeSet(key, cpy) } l.mu.Unlock() return !found } // Clear the value at key from the cache, if it exists func (l *URLLoader) Clear(key uuid.UUID) { l.mu.Lock() delete(l.cache, key) l.mu.Unlock() } func (l *URLLoader) unsafeSet(key uuid.UUID, value []models.URL) { if l.cache == nil { l.cache = map[uuid.UUID][]models.URL{} } l.cache[key] = value } // keyIndex will return the location of the key in the batch, if its not found // it will add the key to the batch func (b *uRLLoaderBatch) keyIndex(l *URLLoader, key uuid.UUID) int { for i, existingKey := range b.keys { if key == existingKey { return i } } pos := len(b.keys) b.keys = append(b.keys, key) if pos == 0 { go b.startTimer(l) } if l.maxBatch != 0 && pos >= l.maxBatch-1 { if !b.closing { b.closing = true l.batch = nil go b.end(l) } } return pos } func (b *uRLLoaderBatch) startTimer(l *URLLoader) { time.Sleep(l.wait) l.mu.Lock() // we must have hit a batch limit and are already finalizing this batch if b.closing { l.mu.Unlock() return } l.batch = nil l.mu.Unlock() b.end(l) } func (b *uRLLoaderBatch) end(l *URLLoader) { b.data, b.error = l.fetch(b.keys) close(b.done) } ================================================ FILE: internal/dataloader/uuidsloader_gen.go ================================================ // Code generated by github.com/vektah/dataloaden, DO NOT EDIT. package dataloader import ( "sync" "time" "github.com/gofrs/uuid" ) // UUIDsLoaderConfig captures the config to create a new UUIDsLoader type UUIDsLoaderConfig struct { // Fetch is a method that provides the data for the loader Fetch func(keys []uuid.UUID) ([][]uuid.UUID, []error) // Wait is how long wait before sending a batch Wait time.Duration // MaxBatch will limit the maximum number of keys to send in one batch, 0 = not limit MaxBatch int } // NewUUIDsLoader creates a new UUIDsLoader given a fetch, wait, and maxBatch func NewUUIDsLoader(config UUIDsLoaderConfig) *UUIDsLoader { return &UUIDsLoader{ fetch: config.Fetch, wait: config.Wait, maxBatch: config.MaxBatch, } } // UUIDsLoader batches and caches requests type UUIDsLoader struct { // this method provides the data for the loader fetch func(keys []uuid.UUID) ([][]uuid.UUID, []error) // how long to done before sending a batch wait time.Duration // this will limit the maximum number of keys to send in one batch, 0 = no limit maxBatch int // INTERNAL // lazily created cache cache map[uuid.UUID][]uuid.UUID // the current batch. keys will continue to be collected until timeout is hit, // then everything will be sent to the fetch method and out to the listeners batch *uUIDsLoaderBatch // mutex to prevent races mu sync.Mutex } type uUIDsLoaderBatch struct { keys []uuid.UUID data [][]uuid.UUID error []error closing bool done chan struct{} } // Load a UUID by key, batching and caching will be applied automatically func (l *UUIDsLoader) Load(key uuid.UUID) ([]uuid.UUID, error) { return l.LoadThunk(key)() } // LoadThunk returns a function that when called will block waiting for a UUID. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *UUIDsLoader) LoadThunk(key uuid.UUID) func() ([]uuid.UUID, error) { l.mu.Lock() if it, ok := l.cache[key]; ok { l.mu.Unlock() return func() ([]uuid.UUID, error) { return it, nil } } if l.batch == nil { l.batch = &uUIDsLoaderBatch{done: make(chan struct{})} } batch := l.batch pos := batch.keyIndex(l, key) l.mu.Unlock() return func() ([]uuid.UUID, error) { <-batch.done var data []uuid.UUID if pos < len(batch.data) { data = batch.data[pos] } var err error // its convenient to be able to return a single error for everything if len(batch.error) == 1 { err = batch.error[0] } else if batch.error != nil { err = batch.error[pos] } if err == nil { l.mu.Lock() l.unsafeSet(key, data) l.mu.Unlock() } return data, err } } // LoadAll fetches many keys at once. It will be broken into appropriate sized // sub batches depending on how the loader is configured func (l *UUIDsLoader) LoadAll(keys []uuid.UUID) ([][]uuid.UUID, []error) { results := make([]func() ([]uuid.UUID, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } uUIDs := make([][]uuid.UUID, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { uUIDs[i], errors[i] = thunk() } return uUIDs, errors } // LoadAllThunk returns a function that when called will block waiting for a UUIDs. // This method should be used if you want one goroutine to make requests to many // different data loaders without blocking until the thunk is called. func (l *UUIDsLoader) LoadAllThunk(keys []uuid.UUID) func() ([][]uuid.UUID, []error) { results := make([]func() ([]uuid.UUID, error), len(keys)) for i, key := range keys { results[i] = l.LoadThunk(key) } return func() ([][]uuid.UUID, []error) { uUIDs := make([][]uuid.UUID, len(keys)) errors := make([]error, len(keys)) for i, thunk := range results { uUIDs[i], errors[i] = thunk() } return uUIDs, errors } } // Prime the cache with the provided key and value. If the key already exists, no change is made // and false is returned. // (To forcefully prime the cache, clear the key first with loader.clear(key).prime(key, value).) func (l *UUIDsLoader) Prime(key uuid.UUID, value []uuid.UUID) bool { l.mu.Lock() var found bool if _, found = l.cache[key]; !found { // make a copy when writing to the cache, its easy to pass a pointer in from a loop var // and end up with the whole cache pointing to the same value. cpy := make([]uuid.UUID, len(value)) copy(cpy, value) l.unsafeSet(key, cpy) } l.mu.Unlock() return !found } // Clear the value at key from the cache, if it exists func (l *UUIDsLoader) Clear(key uuid.UUID) { l.mu.Lock() delete(l.cache, key) l.mu.Unlock() } func (l *UUIDsLoader) unsafeSet(key uuid.UUID, value []uuid.UUID) { if l.cache == nil { l.cache = map[uuid.UUID][]uuid.UUID{} } l.cache[key] = value } // keyIndex will return the location of the key in the batch, if its not found // it will add the key to the batch func (b *uUIDsLoaderBatch) keyIndex(l *UUIDsLoader, key uuid.UUID) int { for i, existingKey := range b.keys { if key == existingKey { return i } } pos := len(b.keys) b.keys = append(b.keys, key) if pos == 0 { go b.startTimer(l) } if l.maxBatch != 0 && pos >= l.maxBatch-1 { if !b.closing { b.closing = true l.batch = nil go b.end(l) } } return pos } func (b *uUIDsLoaderBatch) startTimer(l *UUIDsLoader) { time.Sleep(l.wait) l.mu.Lock() // we must have hit a batch limit and are already finalizing this batch if b.closing { l.mu.Unlock() return } l.batch = nil l.mu.Unlock() b.end(l) } func (b *uUIDsLoaderBatch) end(l *UUIDsLoader) { b.data, b.error = l.fetch(b.keys) close(b.done) } ================================================ FILE: internal/email/manager.go ================================================ package email import ( "errors" "fmt" "time" "github.com/wneessen/go-mail" "github.com/stashapp/stash-box/internal/config" ) type Manager struct { lastEmailed map[string]time.Time } func NewManager() *Manager { return &Manager{ lastEmailed: make(map[string]time.Time), } } func (m *Manager) validateEmailCooldown(email string) error { m.clearExpired() if _, found := m.lastEmailed[email]; found { return errors.New("pending-email-change") } return nil } func (m *Manager) clearExpired() { cd := config.GetEmailCooldown() expireTime := time.Now() expireTime = expireTime.Add(-cd) for e, t := range m.lastEmailed { if t.Before(expireTime) { delete(m.lastEmailed, e) } } } func (m *Manager) Send(email, subject, text, html string) error { err := m.validateEmailCooldown(email) if err != nil { return err } if len(config.GetMissingEmailSettings()) > 0 { return errors.New("email settings not configured") } message := mail.NewMsg() if err := message.FromFormat(config.GetTitle(), config.GetEmailFrom()); err != nil { return fmt.Errorf("failed to set From address: %w", err) } if err := message.To(email); err != nil { return fmt.Errorf("failed to set To address: %w", err) } message.Subject(subject) message.SetBodyString(mail.TypeTextPlain, text) message.AddAlternativeString(mail.TypeTextHTML, html) client, err := mail.NewClient(config.GetEmailHost(), mail.WithPort(config.GetEmailPort()), mail.WithSMTPAuth(mail.SMTPAuthPlain), mail.WithUsername(config.GetEmailUser()), mail.WithPassword(config.GetEmailPassword())) if err != nil { return fmt.Errorf("failed to create mail client: %w", err) } if err := client.DialAndSend(message); err != nil { return fmt.Errorf("failed to send mail: %w", err) } // add to email map m.lastEmailed[email] = time.Now() return nil } ================================================ FILE: internal/email/templates/email.html ================================================ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="x-apple-disable-message-reformatting" /> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta name="color-scheme" content="light dark" /> <meta name="supported-color-schemes" content="light dark" /> <title> {{ .PreHeader }} ================================================ FILE: internal/email/templates/email.txt ================================================ ************ {{ .Greeting }} ************ {{ .Content }} {{ .ActionURL }} - {{ .SiteName }} ================================================ FILE: internal/email/user.go ================================================ package email import ( "bytes" "context" "embed" "fmt" "text/template" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/config" "github.com/stashapp/stash-box/internal/converter" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/internal/queries" ) //go:embed templates/*.html //go:embed templates/*.txt var templateFS embed.FS func ConfirmOldEmail(ctx context.Context, tx *queries.Queries, user models.User, mgr *Manager) error { // generate an activation key and email key, err := generateConfirmOldEmailKey(ctx, tx, user.ID) if err != nil { return err } return sendConfirmOldEmail(mgr, user, *key) } func generateConfirmOldEmailKey(ctx context.Context, tx *queries.Queries, userID uuid.UUID) (*uuid.UUID, error) { data := models.UserTokenData{ UserID: userID, } param, err := converter.CreateUserTokenParamsFromData(models.UserTokenTypeConfirmOldEmail, data) if err != nil { return nil, err } token, err := tx.CreateUserToken(ctx, param) if err != nil { return nil, err } return &token.ID, nil } func ConfirmNewEmail(ctx context.Context, tx *queries.Queries, user models.User, email string, mgr *Manager) error { // generate an activation key and email key, err := generateConfirmNewEmailKey(ctx, tx, user.ID, email) if err != nil { return err } return sendConfirmNewEmail(mgr, &user, email, *key) } func generateConfirmNewEmailKey(ctx context.Context, tx *queries.Queries, userID uuid.UUID, email string) (*uuid.UUID, error) { data := models.ChangeEmailTokenData{ UserID: userID, Email: email, } param, err := converter.CreateUserTokenParamsFromData(models.UserTokenTypeConfirmNewEmail, data) if err != nil { return nil, err } obj, err := tx.CreateUserToken(ctx, param) return &obj.ID, err } func ChangeEmail(ctx context.Context, tx *queries.Queries, token models.ChangeEmailTokenData) error { user, err := tx.FindUser(ctx, token.UserID) if err != nil { return err } return tx.UpdateUserEmail(ctx, queries.UpdateUserEmailParams{ ID: user.ID, Email: token.Email, }) } func sendTemplatedEmail(mgr *Manager, email, subject, preHeader, greeting, content, link, cta string) error { htmlTemplates, err := template.ParseFS(templateFS, "templates/email.html", ) if err != nil { return err } data := struct { SiteName string SiteURL string Content string ActionURL string ActionText string Greeting string PreHeader string }{ SiteURL: config.GetHostURL(), SiteName: config.GetTitle(), Content: content, ActionURL: link, ActionText: cta, Greeting: greeting, PreHeader: preHeader, } var html bytes.Buffer if err := htmlTemplates.Execute(&html, data); err != nil { return err } textTemplate, err := template.ParseFS(templateFS, "templates/email.txt", ) if err != nil { return err } var text bytes.Buffer if err := textTemplate.Execute(&text, data); err != nil { return err } return mgr.Send(email, subject, text.String(), html.String()) } func sendConfirmOldEmail(mgr *Manager, user models.User, activationKey uuid.UUID) error { subject := "Email change requested" link := fmt.Sprintf("%s/users/%s/change-email?key=%s", config.GetHostURL(), user.Name, activationKey) preHeader := "Confirm you want to change your email." greeting := fmt.Sprintf("Hi %s,", user.Name) content := "An email change was requested for your account. Click the button below to confirm you want to continue. The link is only valid for 15 minutes." cta := "Confirm email change" return sendTemplatedEmail(mgr, user.Email, subject, preHeader, greeting, content, link, cta) } func SendNewUserEmail(email string, activationKey uuid.UUID, mgr *Manager) error { subject := "Activate your account" link := fmt.Sprintf("%s/activate?key=%s", config.GetHostURL(), activationKey) preHeader := fmt.Sprintf("Welcome, to activate your %s account, click the button below.", config.GetTitle()) greeting := "Welcome!" content := fmt.Sprintf("To activate your %s account, click the button below. The activation link is valid for %s.", config.GetTitle(), config.GetActivationExpiry()) cta := "Activate account" return sendTemplatedEmail(mgr, email, subject, preHeader, greeting, content, link, cta) } func SendResetPasswordEmail(user queries.User, activationKey uuid.UUID, mgr *Manager) error { subject := fmt.Sprintf("Confirm %s password reset", config.GetTitle()) link := fmt.Sprintf("%s/reset-password?key=%s", config.GetHostURL(), activationKey) preHeader := fmt.Sprintf("A password reset was requested for your %s account. Click the button to continue.", config.GetTitle()) greeting := fmt.Sprintf("Hi %s,", user.Name) content := fmt.Sprintf("A password reset was requested for your %s account. Click the button below to continue. The link is only valid for 15 minutes.", config.GetTitle()) cta := "Reset password" return sendTemplatedEmail(mgr, user.Email, subject, preHeader, greeting, content, link, cta) } func sendConfirmNewEmail(mgr *Manager, user *models.User, email string, activationKey uuid.UUID) error { subject := fmt.Sprintf("Confirm %s email change", config.GetTitle()) link := fmt.Sprintf("%s/users/%s/confirm-email?key=%s", config.GetHostURL(), user.Name, activationKey) preHeader := fmt.Sprintf("To confirm you want to change your %s account email, click the button to continue.", config.GetTitle()) greeting := fmt.Sprintf("Hi %s,", user.Name) content := fmt.Sprintf("To confirm you want to change your %s account email, click the button to continue. The link is only valid for 15 minutes.", config.GetTitle()) cta := "Confirm email change" return sendTemplatedEmail(mgr, email, subject, preHeader, greeting, content, link, cta) } ================================================ FILE: internal/image/cache/cache.go ================================================ package cache import ( "fmt" "io" "os" "path/filepath" "sync" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/config" "github.com/stashapp/stash-box/pkg/logger" ) // CacheManager handles caching of resized images type cacheManager struct { path string } var ( instance *cacheManager once sync.Once ) func GetCacheManager() *cacheManager { once.Do(func() { resizeConfig := config.GetImageResizeConfig() if resizeConfig == nil || !resizeConfig.Enabled || len(resizeConfig.CachePath) == 0 { logger.Debugf("image cache not enabled") return } if err := os.MkdirAll(resizeConfig.CachePath, 0755); err != nil { logger.Errorf("Failed to initialize cache directory: %v", err) return } logger.Debugf("image cache enabled in: %s", resizeConfig.CachePath) instance = &cacheManager{} instance.path = resizeConfig.CachePath }) return instance } func (c *cacheManager) getItemPath(id uuid.UUID, size int) string { filename := fmt.Sprintf("%s_%d", id.String(), size) return filepath.Join(c.path, filename) } func (c *cacheManager) Read(id uuid.UUID, size int) (io.ReadCloser, error) { filePath := c.getItemPath(id, size) return os.Open(filePath) } func (c *cacheManager) Write(id uuid.UUID, size int, data []byte) error { filePath := c.getItemPath(id, size) return os.WriteFile(filePath, data, 0644) } func (c *cacheManager) Delete(id uuid.UUID) error { globPath := filepath.Join(c.path, fmt.Sprintf("%s_*", id.String())) files, err := filepath.Glob(globPath) if err != nil { return err } for _, f := range files { if err := os.Remove(f); err != nil { return err } logger.Debugf("deleted cached image: %s", f) } return nil } ================================================ FILE: internal/image/resize_unix.go ================================================ //go:build unix package image import ( "io" "github.com/davidbyttow/govips/v2/vips" "github.com/stashapp/stash-box/internal/config" "github.com/stashapp/stash-box/internal/models" ) func Resize(reader io.Reader, maxSize int, dbimage *models.Image, fileSize int64) ([]byte, error) { defer vips.ShutdownThread() buffer := make([]byte, fileSize) if _, err := io.ReadFull(reader, buffer); err != nil { return nil, err } image, err := vips.NewThumbnailFromBuffer(buffer, maxSize, maxSize, vips.InterestingNone) if err != nil { return nil, err } format := image.Format() if format == vips.ImageTypePNG { ep := vips.NewWebpExportParams() ep.StripMetadata = true ep.Lossless = true imageBytes, _, err := image.ExportWebp(ep) return imageBytes, err } ep := vips.NewJpegExportParams() ep.StripMetadata = true ep.Quality = config.GetImageJpegQuality() ep.Interlace = true ep.OptimizeCoding = true ep.SubsampleMode = vips.VipsForeignSubsampleAuto imageBytes, _, err := image.ExportJpeg(ep) return imageBytes, err } func InitResizer() error { vips.LoggingSettings(nil, vips.LogLevelWarning) return vips.Startup(&vips.Config{MaxCacheSize: 0, MaxCacheMem: 0}) } ================================================ FILE: internal/image/resize_windows.go ================================================ //go:build windows || darwin package image import ( "bytes" "image" "image/jpeg" "image/png" "io" "github.com/disintegration/imaging" "github.com/stashapp/stash-box/internal/config" "github.com/stashapp/stash-box/internal/models" ) func Resize(reader io.Reader, max int, dbimage *models.Image, fileSize int64) ([]byte, error) { return resizeImage(reader, int64(max)) } func InitResizer() error { return nil } func resizeImage(srcReader io.Reader, maxDimension int64) ([]byte, error) { var resizedImage image.Image srcImage, format, err := image.Decode(srcReader) if err != nil { return nil, err } // if height is longer then resize by height instead of width if dim := srcImage.Bounds().Max; dim.Y > dim.X { resizedImage = imaging.Resize(srcImage, 0, int(maxDimension), imaging.MitchellNetravali) } else { resizedImage = imaging.Resize(srcImage, int(maxDimension), 0, imaging.MitchellNetravali) } buf := new(bytes.Buffer) if format == "png" { err = png.Encode(buf, resizedImage) if err != nil { return nil, err } } else { options := jpeg.Options{ Quality: config.GetImageJpegQuality(), } err = jpeg.Encode(buf, resizedImage, &options) if err != nil { return nil, err } } return buf.Bytes(), nil } ================================================ FILE: internal/image/sort.go ================================================ package image import ( "sort" "github.com/stashapp/stash-box/internal/models" ) func OrderLandscape(p []models.Image) { sort.Slice(p, func(a, b int) bool { if p[a].Height == 0 || p[b].Height == 0 { return false } aspectA := p[a].Width / p[a].Height aspectB := p[b].Width / p[b].Height if aspectA > aspectB { return true } else if aspectA < aspectB { return false } return p[a].Width > p[b].Width }) } func OrderPortrait(p []models.Image) { sort.Slice(p, func(a, b int) bool { if p[a].Width == 0 || p[b].Width == 0 { return false } aspectA := p[a].Height / p[a].Width aspectB := p[b].Height / p[b].Width if aspectA > aspectB { return true } else if aspectA < aspectB { return false } return p[a].Height > p[b].Height }) } ================================================ FILE: internal/models/assign/assign.go ================================================ package assign import ( "reflect" "github.com/gofrs/uuid" ) type StringEnum interface { IsValid() bool String() string } // String assigns string value from input if not nil func String(out *string, in *string) { if in != nil { *out = *in } } // StringPtr assigns string pointer value with three-way logic: input, old, or keep existing func StringPtr(out **string, in *string, old *string) { if in != nil { *out = in } else if old != nil { *out = nil } } // IntPtr assigns int pointer value from int input with three-way logic func IntPtr(out **int, in *int, old *int) { if in != nil { val := int(*in) *out = &val } else if old != nil { *out = nil } } // NullUUID assigns uuid.NullUUID value with three-way logic func NullUUID(out *uuid.NullUUID, in *uuid.UUID, old *uuid.UUID) { if in != nil { out.UUID = *in out.Valid = true } else if old != nil { *out = uuid.NullUUID{} } } // EnumPtr assigns enum pointer value with three-way logic using generics func EnumPtr[T StringEnum](out **T, in *string, old *string) { if in != nil { // Use reflection to create an enum from string var zero T enumType := reflect.TypeOf(zero) enumVal := reflect.New(enumType).Elem() enumVal.SetString(*in) enum := enumVal.Interface().(T) *out = &enum } else if old != nil { *out = nil } } ================================================ FILE: internal/models/extension_criterion_input.go ================================================ package models type MultiCriterionInput interface { Count() int GetValues() []interface{} GetModifier() CriterionModifier } func (i MultiIDCriterionInput) Count() int { return len(i.Value) } func (i MultiIDCriterionInput) GetValues() []interface{} { args := make([]interface{}, len(i.Value)) for index := range i.Value { args[index] = i.Value[index] } return args } func (i MultiIDCriterionInput) GetModifier() CriterionModifier { return i.Modifier } func (i MultiStringCriterionInput) Count() int { return len(i.Value) } func (i MultiStringCriterionInput) GetModifier() CriterionModifier { return i.Modifier } func (i MultiStringCriterionInput) GetValues() []interface{} { args := make([]interface{}, len(i.Value)) for index := range i.Value { args[index] = i.Value[index] } return args } ================================================ FILE: internal/models/extension_edit_details.go ================================================ package models import ( "github.com/gofrs/uuid" "github.com/stashapp/stash-box/pkg/utils" ) func (e TagEditDetailsInput) TagEditFromDiff(orig Tag, inputArgs utils.ArgumentsQuery) TagEditData { newData := &TagEdit{} oldData := &TagEdit{} ed := editDiff{} if e.Name != nil || inputArgs.Field("name").IsNull() { oldData.Name, newData.Name = ed.string(&orig.Name, e.Name) } if e.Description != nil || inputArgs.Field("description").IsNull() { oldData.Description, newData.Description = ed.string(orig.Description, e.Description) } if e.CategoryID != nil || inputArgs.Field("category_id").IsNull() { oldData.CategoryID, newData.CategoryID = ed.nullUUID(orig.CategoryID, e.CategoryID) } return TagEditData{ New: newData, Old: oldData, } } func (e TagEditDetailsInput) TagEditFromMerge(orig Tag, sources []uuid.UUID, inputArgs utils.ArgumentsQuery) TagEditData { data := e.TagEditFromDiff(orig, inputArgs) data.MergeSources = sources return data } func (e TagEditDetailsInput) TagEditFromCreate(inputArgs utils.ArgumentsQuery) TagEditData { ret := e.TagEditFromDiff(Tag{}, inputArgs) return TagEditData{ New: ret.New, } } func (e PerformerEditDetailsInput) PerformerEditFromDiff(orig Performer, inputArgs utils.ArgumentsQuery) (*PerformerEditData, error) { if err := ValidateFuzzyString(e.Birthdate); err != nil { return nil, err } if err := ValidateFuzzyString(e.Deathdate); err != nil { return nil, err } newData := &PerformerEdit{} oldData := &PerformerEdit{} ed := editDiff{} if e.Name != nil || inputArgs.Field("name").IsNull() { oldData.Name, newData.Name = ed.string(&orig.Name, e.Name) } if e.Disambiguation != nil || inputArgs.Field("disambiguation").IsNull() { oldData.Disambiguation, newData.Disambiguation = ed.string(orig.Disambiguation, e.Disambiguation) } if e.Gender != nil || inputArgs.Field("gender").IsNull() { oldData.Gender, newData.Gender = ed.enum(orig.Gender, e.Gender) } if e.Birthdate != nil || inputArgs.Field("birthdate").IsNull() { oldData.Birthdate, newData.Birthdate = ed.string(orig.BirthDate, e.Birthdate) } if e.Deathdate != nil || inputArgs.Field("deathdate").IsNull() { oldData.Deathdate, newData.Deathdate = ed.string(orig.DeathDate, e.Deathdate) } if e.Ethnicity != nil || inputArgs.Field("ethnicity").IsNull() { oldData.Ethnicity, newData.Ethnicity = ed.enum(orig.Ethnicity, e.Ethnicity) } if e.Country != nil || inputArgs.Field("country").IsNull() { oldData.Country, newData.Country = ed.string(orig.Country, e.Country) } if e.EyeColor != nil || inputArgs.Field("eye_color").IsNull() { oldData.EyeColor, newData.EyeColor = ed.enum(orig.EyeColor, e.EyeColor) } if e.HairColor != nil || inputArgs.Field("hair_color").IsNull() { oldData.HairColor, newData.HairColor = ed.enum(orig.HairColor, e.HairColor) } if e.Height != nil || inputArgs.Field("height").IsNull() { oldData.Height, newData.Height = ed.int(orig.Height, e.Height) } if e.CupSize != nil || inputArgs.Field("cup_size").IsNull() { oldData.CupSize, newData.CupSize = ed.string(orig.CupSize, e.CupSize) } if e.BandSize != nil || inputArgs.Field("band_size").IsNull() { oldData.BandSize, newData.BandSize = ed.int(orig.BandSize, e.BandSize) } if e.WaistSize != nil || inputArgs.Field("waist_size").IsNull() { oldData.WaistSize, newData.WaistSize = ed.int(orig.WaistSize, e.WaistSize) } if e.HipSize != nil || inputArgs.Field("hip_size").IsNull() { oldData.HipSize, newData.HipSize = ed.int(orig.HipSize, e.HipSize) } if e.BreastType != nil || inputArgs.Field("breast_type").IsNull() { oldData.BreastType, newData.BreastType = ed.enum(orig.BreastType, e.BreastType) } if e.CareerStartYear != nil || inputArgs.Field("career_start_year").IsNull() { oldData.CareerStartYear, newData.CareerStartYear = ed.int(orig.CareerStartYear, e.CareerStartYear) } if e.CareerEndYear != nil || inputArgs.Field("career_end_year").IsNull() { oldData.CareerEndYear, newData.CareerEndYear = ed.int(orig.CareerEndYear, e.CareerEndYear) } return &PerformerEditData{ New: newData, Old: oldData, }, nil } func (e PerformerEditDetailsInput) PerformerEditFromMerge(orig Performer, sources []uuid.UUID, inputArgs utils.ArgumentsQuery) (*PerformerEditData, error) { data, err := e.PerformerEditFromDiff(orig, inputArgs) if err != nil { return nil, err } data.MergeSources = sources return data, nil } func (e PerformerEditDetailsInput) PerformerEditFromCreate(inputArgs utils.ArgumentsQuery) (*PerformerEditData, error) { ret, err := e.PerformerEditFromDiff(Performer{}, inputArgs) if err != nil { return nil, err } return &PerformerEditData{ New: ret.New, }, nil } func (e StudioEditDetailsInput) StudioEditFromDiff(orig Studio, inputArgs utils.ArgumentsQuery) (*StudioEditData, error) { newData := &StudioEdit{} oldData := &StudioEdit{} ed := editDiff{} if e.Name != nil || inputArgs.Field("name").IsNull() { oldData.Name, newData.Name = ed.string(&orig.Name, e.Name) } if e.ParentID != nil || inputArgs.Field("parent_id").IsNull() { oldData.ParentID, newData.ParentID = ed.nullUUID(orig.ParentStudioID, e.ParentID) } return &StudioEditData{ New: newData, Old: oldData, }, nil } func (e StudioEditDetailsInput) StudioEditFromMerge(orig Studio, sources []uuid.UUID, inputArgs utils.ArgumentsQuery) (*StudioEditData, error) { data, err := e.StudioEditFromDiff(orig, inputArgs) data.MergeSources = sources return data, err } func (e StudioEditDetailsInput) StudioEditFromCreate() StudioEditData { newData := &StudioEdit{} ed := editDiff{} _, newData.Name = ed.string(nil, e.Name) _, newData.ParentID = ed.nullUUID(uuid.NullUUID{}, e.ParentID) return StudioEditData{ New: newData, } } func (e SceneEditDetailsInput) SceneEditFromDiff(orig Scene, inputArgs utils.ArgumentsQuery) (*SceneEditData, error) { if err := ValidateFuzzyString(e.Date); err != nil { return nil, err } newData := &SceneEdit{} oldData := &SceneEdit{} ed := editDiff{} if e.Title != nil || inputArgs.Field("title").IsNull() { oldData.Title, newData.Title = ed.string(orig.Title, e.Title) } if e.Details != nil || inputArgs.Field("details").IsNull() { oldData.Details, newData.Details = ed.string(orig.Details, e.Details) } if e.Date != nil || inputArgs.Field("date").IsNull() { oldData.Date, newData.Date = ed.string(orig.Date, e.Date) } if e.ProductionDate != nil || inputArgs.Field("production_date").IsNull() { oldData.ProductionDate, newData.ProductionDate = ed.string(orig.ProductionDate, e.ProductionDate) } if e.StudioID != nil || inputArgs.Field("studio_id").IsNull() { oldData.StudioID, newData.StudioID = ed.nullUUID(orig.StudioID, e.StudioID) } if e.Duration != nil || inputArgs.Field("duration").IsNull() { oldData.Duration, newData.Duration = ed.int(orig.Duration, e.Duration) } if e.Director != nil || inputArgs.Field("director").IsNull() { oldData.Director, newData.Director = ed.string(orig.Director, e.Director) } if e.Code != nil || inputArgs.Field("code").IsNull() { oldData.Code, newData.Code = ed.string(orig.Code, e.Code) } return &SceneEditData{ New: newData, Old: oldData, }, nil } func (e SceneEditDetailsInput) SceneEditFromMerge(orig Scene, sources []uuid.UUID, inputArgs utils.ArgumentsQuery) (*SceneEditData, error) { data, err := e.SceneEditFromDiff(orig, inputArgs) if err != nil { return nil, err } data.MergeSources = sources return data, nil } func (e SceneEditDetailsInput) SceneEditFromCreate(inputArgs utils.ArgumentsQuery) (*SceneEditData, error) { ret, err := e.SceneEditFromDiff(Scene{}, inputArgs) if err != nil { return nil, err } return &SceneEditData{ New: ret.New, }, nil } ================================================ FILE: internal/models/extension_edit_details_test.go ================================================ package models import ( "testing" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/pkg/utils" "github.com/stretchr/testify/assert" ) var ( aName = "aName" bName = "bName" aDescription = "aDescription" bDescription = "bDescription" aCategoryID = uuid.FromStringOrNil("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa") bCategoryID = uuid.FromStringOrNil("bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb") aDisambiguation = "aDisambiguation" bDisambiguation = "bDisambiguation" aGender = GenderEnumMale bGender = GenderEnumFemale aGenderStr = aGender.String() bGenderStr = bGender.String() aDate = "2001-01-01" bDate = "2002-01" dDate = "2024-11" aEthnicity = EthnicityEnumAsian bEthnicity = EthnicityEnumBlack aEthnicityStr = aEthnicity.String() bEthnicityStr = bEthnicity.String() aCountry = "aCountry" bCountry = "bCountry" aEyeColor = EyeColorEnumBlue bEyeColor = EyeColorEnumBrown aEyeColorStr = aEyeColor.String() bEyeColorStr = bEyeColor.String() aHairColor = HairColorEnumAuburn bHairColor = HairColorEnumBlack aHairColorStr = aHairColor.String() bHairColorStr = bHairColor.String() aHeight = 100 bHeight = 200 aHeight64 = aHeight bHeight64 = bHeight aCupSize = "aCupSize" bCupSize = "bCupSize" aBandSize = 30 bBandSize = 40 aWaistSize = 50 bWaistSize = 60 aHipSize = 70 bHipSize = 80 aBandSize64 = aBandSize bBandSize64 = bBandSize aWaistSize64 = aWaistSize bWaistSize64 = bWaistSize aHipSize64 = aHipSize bHipSize64 = bHipSize aBreastType = BreastTypeEnumFake bBreastType = BreastTypeEnumNatural aBreastTypeStr = aBreastType.String() bBreastTypeStr = bBreastType.String() aStartYear = 2001 aEndYear = 2002 bStartYear = 2003 bEndYear = 2004 aStartYear64 = aStartYear aEndYear64 = aEndYear bStartYear64 = bStartYear bEndYear64 = bEndYear ) var mockedArguments = utils.ArgumentsQuery{} func TestTagEditFromDiff(t *testing.T) { orig := Tag{ Name: aName, Description: &aDescription, CategoryID: uuid.NullUUID{UUID: aCategoryID, Valid: true}, } input := TagEditDetailsInput{ Name: &bName, Description: &bDescription, CategoryID: &bCategoryID, } out := input.TagEditFromDiff(orig, mockedArguments) assert.Equal(t, TagEditData{ New: &TagEdit{ Name: &bName, Description: &bDescription, CategoryID: &bCategoryID, }, Old: &TagEdit{ Name: &aName, Description: &aDescription, CategoryID: &aCategoryID, }, }, out) emptyOrig := Tag{ Name: aName, } out = input.TagEditFromDiff(emptyOrig, mockedArguments) assert.Equal(t, TagEditData{ New: &TagEdit{ Name: &bName, Description: &bDescription, CategoryID: &bCategoryID, }, Old: &TagEdit{ Name: &aName, }, }, out) emptyInput := TagEditDetailsInput{} out = emptyInput.TagEditFromDiff(orig, mockedArguments) assert.Equal(t, TagEditData{ New: &TagEdit{}, Old: &TagEdit{}, }, out) equalInput := TagEditDetailsInput{ Name: &aName, Description: &aDescription, CategoryID: &aCategoryID, } out = equalInput.TagEditFromDiff(orig, mockedArguments) assert.Equal(t, TagEditData{ New: &TagEdit{}, Old: &TagEdit{}, }, out) } func TestPerformerEditFromDiff(t *testing.T) { orig := Performer{ Name: aName, Disambiguation: &aDisambiguation, Gender: &aGender, BirthDate: &aDate, Ethnicity: &aEthnicity, Country: &aCountry, EyeColor: &aEyeColor, HairColor: &aHairColor, Height: &aHeight, CupSize: &aCupSize, BandSize: &aBandSize, WaistSize: &aWaistSize, HipSize: &aHipSize, BreastType: &aBreastType, CareerStartYear: &aStartYear, CareerEndYear: &aEndYear, } input := PerformerEditDetailsInput{ Name: &bName, Disambiguation: &bDisambiguation, Gender: &bGender, Birthdate: &bDate, Deathdate: &dDate, Ethnicity: &bEthnicity, Country: &bCountry, EyeColor: &bEyeColor, HairColor: &bHairColor, Height: &bHeight, CupSize: &bCupSize, BandSize: &bBandSize, WaistSize: &bWaistSize, HipSize: &bHipSize, BreastType: &bBreastType, CareerStartYear: &bStartYear, CareerEndYear: &bEndYear, } out, _ := input.PerformerEditFromDiff(orig, mockedArguments) assert.Equal(t, PerformerEditData{ New: &PerformerEdit{ Name: &bName, Disambiguation: &bDisambiguation, Gender: &bGenderStr, Birthdate: &bDate, Deathdate: &dDate, Ethnicity: &bEthnicityStr, Country: &bCountry, EyeColor: &bEyeColorStr, HairColor: &bHairColorStr, Height: &bHeight64, CupSize: &bCupSize, BandSize: &bBandSize64, WaistSize: &bWaistSize64, HipSize: &bHipSize64, BreastType: &bBreastTypeStr, CareerStartYear: &bStartYear64, CareerEndYear: &bEndYear64, }, Old: &PerformerEdit{ Name: &aName, Disambiguation: &aDisambiguation, Gender: &aGenderStr, Birthdate: &aDate, Ethnicity: &aEthnicityStr, Country: &aCountry, EyeColor: &aEyeColorStr, HairColor: &aHairColorStr, Height: &aHeight64, CupSize: &aCupSize, BandSize: &aBandSize64, WaistSize: &aWaistSize64, HipSize: &aHipSize64, BreastType: &aBreastTypeStr, CareerStartYear: &aStartYear64, CareerEndYear: &aEndYear64, }, }, *out) emptyOrig := Performer{ Name: aName, } out, _ = input.PerformerEditFromDiff(emptyOrig, mockedArguments) assert.Equal(t, PerformerEditData{ New: &PerformerEdit{ Name: &bName, Disambiguation: &bDisambiguation, Gender: &bGenderStr, Birthdate: &bDate, Deathdate: &dDate, Ethnicity: &bEthnicityStr, Country: &bCountry, EyeColor: &bEyeColorStr, HairColor: &bHairColorStr, Height: &bHeight64, CupSize: &bCupSize, BandSize: &bBandSize64, WaistSize: &bWaistSize64, HipSize: &bHipSize64, BreastType: &bBreastTypeStr, CareerStartYear: &bStartYear64, CareerEndYear: &bEndYear64, }, Old: &PerformerEdit{ Name: &aName, }, }, *out) emptyInput := PerformerEditDetailsInput{} out, _ = emptyInput.PerformerEditFromDiff(orig, mockedArguments) assert.Equal(t, PerformerEditData{ New: &PerformerEdit{}, Old: &PerformerEdit{}, }, *out) equalInput := PerformerEditDetailsInput{ Name: &aName, Disambiguation: &aDisambiguation, Gender: &aGender, Birthdate: &aDate, Ethnicity: &aEthnicity, Country: &aCountry, EyeColor: &aEyeColor, HairColor: &aHairColor, Height: &aHeight, CupSize: &aCupSize, BandSize: &aBandSize, WaistSize: &aWaistSize, HipSize: &aHipSize, BreastType: &aBreastType, CareerStartYear: &aStartYear, CareerEndYear: &aEndYear, } out, _ = equalInput.PerformerEditFromDiff(orig, mockedArguments) assert.Equal(t, PerformerEditData{ New: &PerformerEdit{}, Old: &PerformerEdit{}, }, *out) } ================================================ FILE: internal/models/extension_role_enum.go ================================================ package models func (r RoleEnum) Implies(other RoleEnum) bool { // admin has all roles if r == RoleEnumAdmin { return true } // MANAGE_INVITES implies INVITE if r == RoleEnumManageInvites && other == RoleEnumInvite { return true } // until we add a NONE value, all values imply read if r.IsValid() && other == RoleEnumRead { return true } // all others only imply themselves return r == other } ================================================ FILE: internal/models/generate.go ================================================ //go:generate go run github.com/99designs/gqlgen package models ================================================ FILE: internal/models/generated_exec.go ================================================ // Code generated by github.com/99designs/gqlgen, DO NOT EDIT. package models import ( "bytes" "context" "errors" "fmt" "strconv" "sync/atomic" "time" "github.com/99designs/gqlgen/graphql" "github.com/99designs/gqlgen/graphql/introspection" "github.com/gofrs/uuid" gqlparser "github.com/vektah/gqlparser/v2" "github.com/vektah/gqlparser/v2/ast" ) // region ************************** generated!.gotpl ************************** // NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface. func NewExecutableSchema(cfg Config) graphql.ExecutableSchema { return &executableSchema{SchemaData: cfg.Schema, Resolvers: cfg.Resolvers, Directives: cfg.Directives, ComplexityRoot: cfg.Complexity} } type Config = graphql.Config[ResolverRoot, DirectiveRoot, ComplexityRoot] type ResolverRoot interface { Draft() DraftResolver Edit() EditResolver EditComment() EditCommentResolver EditVote() EditVoteResolver Image() ImageResolver ModAudit() ModAuditResolver Mutation() MutationResolver Notification() NotificationResolver Performer() PerformerResolver PerformerDraft() PerformerDraftResolver PerformerEdit() PerformerEditResolver Query() QueryResolver QueryEditsResultType() QueryEditsResultTypeResolver QueryExistingPerformerResult() QueryExistingPerformerResultResolver QueryExistingSceneResult() QueryExistingSceneResultResolver QueryModAuditsResultType() QueryModAuditsResultTypeResolver QueryNotificationsResult() QueryNotificationsResultResolver QueryPerformersResultType() QueryPerformersResultTypeResolver QueryScenesResultType() QueryScenesResultTypeResolver Scene() SceneResolver SceneDraft() SceneDraftResolver SceneEdit() SceneEditResolver Site() SiteResolver Studio() StudioResolver StudioEdit() StudioEditResolver Tag() TagResolver TagCategory() TagCategoryResolver TagEdit() TagEditResolver URL() URLResolver User() UserResolver } type DirectiveRoot struct { HasRole func(ctx context.Context, obj any, next graphql.Resolver, role RoleEnum) (res any, err error) IsUserOwner func(ctx context.Context, obj any, next graphql.Resolver) (res any, err error) } type ComplexityRoot struct { BodyModification struct { Description func(childComplexity int) int Location func(childComplexity int) int } CommentCommentedEdit struct { Comment func(childComplexity int) int } CommentOwnEdit struct { Comment func(childComplexity int) int } CommentVotedEdit struct { Comment func(childComplexity int) int } DownvoteOwnEdit struct { Edit func(childComplexity int) int } Draft struct { Created func(childComplexity int) int Data func(childComplexity int) int Expires func(childComplexity int) int ID func(childComplexity int) int } DraftEntity struct { ID func(childComplexity int) int Name func(childComplexity int) int } DraftFingerprint struct { Algorithm func(childComplexity int) int Duration func(childComplexity int) int Hash func(childComplexity int) int } DraftSubmissionStatus struct { ID func(childComplexity int) int } Edit struct { Applied func(childComplexity int) int Bot func(childComplexity int) int Closed func(childComplexity int) int Comments func(childComplexity int) int Created func(childComplexity int) int Destructive func(childComplexity int) int Details func(childComplexity int) int Expires func(childComplexity int) int ID func(childComplexity int) int MergeSources func(childComplexity int) int OldDetails func(childComplexity int) int Operation func(childComplexity int) int Options func(childComplexity int) int Status func(childComplexity int) int Target func(childComplexity int) int TargetType func(childComplexity int) int Updatable func(childComplexity int) int UpdateCount func(childComplexity int) int Updated func(childComplexity int) int User func(childComplexity int) int VoteCount func(childComplexity int) int Votes func(childComplexity int) int } EditComment struct { Comment func(childComplexity int) int Date func(childComplexity int) int Edit func(childComplexity int) int ID func(childComplexity int) int User func(childComplexity int) int } EditVote struct { Date func(childComplexity int) int User func(childComplexity int) int Vote func(childComplexity int) int } FailedOwnEdit struct { Edit func(childComplexity int) int } FavoritePerformerEdit struct { Edit func(childComplexity int) int } FavoritePerformerScene struct { Scene func(childComplexity int) int } FavoriteStudioEdit struct { Edit func(childComplexity int) int } FavoriteStudioScene struct { Scene func(childComplexity int) int } Fingerprint struct { Algorithm func(childComplexity int) int Created func(childComplexity int) int Duration func(childComplexity int) int Hash func(childComplexity int) int Reports func(childComplexity int) int Submissions func(childComplexity int) int Updated func(childComplexity int) int UserReported func(childComplexity int) int UserSubmitted func(childComplexity int) int } FingerprintSubmissionResult struct { Error func(childComplexity int) int Hash func(childComplexity int) int SceneID func(childComplexity int) int } FingerprintedSceneEdit struct { Edit func(childComplexity int) int } FuzzyDate struct { Accuracy func(childComplexity int) int Date func(childComplexity int) int } GenderFacet struct { Count func(childComplexity int) int Gender func(childComplexity int) int } Image struct { Height func(childComplexity int) int ID func(childComplexity int) int URL func(childComplexity int) int Width func(childComplexity int) int } InviteKey struct { Expires func(childComplexity int) int ID func(childComplexity int) int Uses func(childComplexity int) int } Measurements struct { BandSize func(childComplexity int) int CupSize func(childComplexity int) int Hip func(childComplexity int) int Waist func(childComplexity int) int } ModAudit struct { Action func(childComplexity int) int CreatedAt func(childComplexity int) int Data func(childComplexity int) int ID func(childComplexity int) int Reason func(childComplexity int) int TargetID func(childComplexity int) int TargetType func(childComplexity int) int User func(childComplexity int) int } Mutation struct { ActivateNewUser func(childComplexity int, input ActivateNewUserInput) int AmendEdit func(childComplexity int, input AmendEditInput) int ApplyEdit func(childComplexity int, input ApplyEditInput) int CancelEdit func(childComplexity int, input CancelEditInput) int ChangePassword func(childComplexity int, input UserChangePasswordInput) int ConfirmChangeEmail func(childComplexity int, token uuid.UUID) int DeleteEdit func(childComplexity int, input DeleteEditInput) int DestroyDraft func(childComplexity int, id uuid.UUID) int EditComment func(childComplexity int, input EditCommentInput) int EditVote func(childComplexity int, input EditVoteInput) int FavoritePerformer func(childComplexity int, id uuid.UUID, favorite bool) int FavoriteStudio func(childComplexity int, id uuid.UUID, favorite bool) int GenerateInviteCode func(childComplexity int) int GenerateInviteCodes func(childComplexity int, input *GenerateInviteCodeInput) int GrantInvite func(childComplexity int, input GrantInviteInput) int ImageCreate func(childComplexity int, input ImageCreateInput) int ImageDestroy func(childComplexity int, input ImageDestroyInput) int MarkNotificationsRead func(childComplexity int, notification *MarkNotificationReadInput) int NewUser func(childComplexity int, input NewUserInput) int PerformerCreate func(childComplexity int, input PerformerCreateInput) int PerformerDestroy func(childComplexity int, input PerformerDestroyInput) int PerformerEdit func(childComplexity int, input PerformerEditInput) int PerformerEditUpdate func(childComplexity int, id uuid.UUID, input PerformerEditInput) int PerformerUpdate func(childComplexity int, input PerformerUpdateInput) int RegenerateAPIKey func(childComplexity int, userID *uuid.UUID) int RequestChangeEmail func(childComplexity int) int RescindInviteCode func(childComplexity int, code uuid.UUID) int ResetPassword func(childComplexity int, input ResetPasswordInput) int RevokeInvite func(childComplexity int, input RevokeInviteInput) int SceneCreate func(childComplexity int, input SceneCreateInput) int SceneDeleteFingerprintSubmissions func(childComplexity int, input DeleteFingerprintSubmissionsInput) int SceneDestroy func(childComplexity int, input SceneDestroyInput) int SceneEdit func(childComplexity int, input SceneEditInput) int SceneEditUpdate func(childComplexity int, id uuid.UUID, input SceneEditInput) int SceneMoveFingerprintSubmissions func(childComplexity int, input MoveFingerprintSubmissionsInput) int SceneUpdate func(childComplexity int, input SceneUpdateInput) int SiteCreate func(childComplexity int, input SiteCreateInput) int SiteDestroy func(childComplexity int, input SiteDestroyInput) int SiteUpdate func(childComplexity int, input SiteUpdateInput) int StudioCreate func(childComplexity int, input StudioCreateInput) int StudioDestroy func(childComplexity int, input StudioDestroyInput) int StudioEdit func(childComplexity int, input StudioEditInput) int StudioEditUpdate func(childComplexity int, id uuid.UUID, input StudioEditInput) int StudioUpdate func(childComplexity int, input StudioUpdateInput) int SubmitFingerprint func(childComplexity int, input FingerprintSubmission) int SubmitFingerprints func(childComplexity int, input []FingerprintBatchSubmission) int SubmitPerformerDraft func(childComplexity int, input PerformerDraftInput) int SubmitSceneDraft func(childComplexity int, input SceneDraftInput) int TagCategoryCreate func(childComplexity int, input TagCategoryCreateInput) int TagCategoryDestroy func(childComplexity int, input TagCategoryDestroyInput) int TagCategoryUpdate func(childComplexity int, input TagCategoryUpdateInput) int TagCreate func(childComplexity int, input TagCreateInput) int TagDestroy func(childComplexity int, input TagDestroyInput) int TagEdit func(childComplexity int, input TagEditInput) int TagEditUpdate func(childComplexity int, id uuid.UUID, input TagEditInput) int TagUpdate func(childComplexity int, input TagUpdateInput) int UpdateNotificationSubscriptions func(childComplexity int, subscriptions []NotificationEnum) int UserCreate func(childComplexity int, input UserCreateInput) int UserDestroy func(childComplexity int, input UserDestroyInput) int UserUpdate func(childComplexity int, input UserUpdateInput) int ValidateChangeEmail func(childComplexity int, token uuid.UUID, email string) int } Notification struct { Created func(childComplexity int) int Data func(childComplexity int) int Read func(childComplexity int) int } Performer struct { Age func(childComplexity int) int Aliases func(childComplexity int) int BandSize func(childComplexity int) int BirthDate func(childComplexity int) int Birthdate func(childComplexity int) int BreastType func(childComplexity int) int CareerEndYear func(childComplexity int) int CareerStartYear func(childComplexity int) int Country func(childComplexity int) int Created func(childComplexity int) int CupSize func(childComplexity int) int DeathDate func(childComplexity int) int Deleted func(childComplexity int) int Disambiguation func(childComplexity int) int Edits func(childComplexity int) int Ethnicity func(childComplexity int) int EyeColor func(childComplexity int) int Gender func(childComplexity int) int HairColor func(childComplexity int) int Height func(childComplexity int) int HipSize func(childComplexity int) int ID func(childComplexity int) int Images func(childComplexity int) int IsFavorite func(childComplexity int) int Measurements func(childComplexity int) int MergedIds func(childComplexity int) int MergedIntoID func(childComplexity int) int Name func(childComplexity int) int Piercings func(childComplexity int) int SceneCount func(childComplexity int) int Scenes func(childComplexity int, input *PerformerScenesInput) int Studios func(childComplexity int, studioID *uuid.UUID) int Tattoos func(childComplexity int) int Updated func(childComplexity int) int Urls func(childComplexity int) int WaistSize func(childComplexity int) int } PerformerAppearance struct { As func(childComplexity int) int Performer func(childComplexity int) int } PerformerDraft struct { Aliases func(childComplexity int) int Birthdate func(childComplexity int) int BreastType func(childComplexity int) int CareerEndYear func(childComplexity int) int CareerStartYear func(childComplexity int) int Country func(childComplexity int) int Deathdate func(childComplexity int) int Disambiguation func(childComplexity int) int Ethnicity func(childComplexity int) int EyeColor func(childComplexity int) int Gender func(childComplexity int) int HairColor func(childComplexity int) int Height func(childComplexity int) int ID func(childComplexity int) int Image func(childComplexity int) int Measurements func(childComplexity int) int Name func(childComplexity int) int Piercings func(childComplexity int) int Tattoos func(childComplexity int) int Urls func(childComplexity int) int } PerformerEdit struct { AddedAliases func(childComplexity int) int AddedImages func(childComplexity int) int AddedPiercings func(childComplexity int) int AddedTattoos func(childComplexity int) int AddedUrls func(childComplexity int) int Aliases func(childComplexity int) int BandSize func(childComplexity int) int Birthdate func(childComplexity int) int BreastType func(childComplexity int) int CareerEndYear func(childComplexity int) int CareerStartYear func(childComplexity int) int Country func(childComplexity int) int CupSize func(childComplexity int) int Deathdate func(childComplexity int) int Disambiguation func(childComplexity int) int DraftID func(childComplexity int) int Ethnicity func(childComplexity int) int EyeColor func(childComplexity int) int Gender func(childComplexity int) int HairColor func(childComplexity int) int Height func(childComplexity int) int HipSize func(childComplexity int) int Images func(childComplexity int) int Name func(childComplexity int) int Piercings func(childComplexity int) int RemovedAliases func(childComplexity int) int RemovedImages func(childComplexity int) int RemovedPiercings func(childComplexity int) int RemovedTattoos func(childComplexity int) int RemovedUrls func(childComplexity int) int Tattoos func(childComplexity int) int Urls func(childComplexity int) int WaistSize func(childComplexity int) int } PerformerEditOptions struct { SetMergeAliases func(childComplexity int) int SetModifyAliases func(childComplexity int) int } PerformerSearchFacets struct { Genders func(childComplexity int) int } PerformerStudio struct { SceneCount func(childComplexity int) int Studio func(childComplexity int) int } Query struct { FindDraft func(childComplexity int, id uuid.UUID) int FindDrafts func(childComplexity int) int FindEdit func(childComplexity int, id uuid.UUID) int FindPerformer func(childComplexity int, id uuid.UUID) int FindScene func(childComplexity int, id uuid.UUID) int FindScenesBySceneFingerprints func(childComplexity int, fingerprints [][]FingerprintQueryInput) int FindSite func(childComplexity int, id uuid.UUID) int FindStudio func(childComplexity int, id *uuid.UUID, name *string) int FindTag func(childComplexity int, id *uuid.UUID, name *string) int FindTagCategory func(childComplexity int, id uuid.UUID) int FindTagOrAlias func(childComplexity int, name string) int FindUser func(childComplexity int, id *uuid.UUID, username *string) int GetConfig func(childComplexity int) int GetUnreadNotificationCount func(childComplexity int) int Me func(childComplexity int) int QueryEdits func(childComplexity int, input EditQueryInput) int QueryExistingPerformer func(childComplexity int, input QueryExistingPerformerInput) int QueryExistingScene func(childComplexity int, input QueryExistingSceneInput) int QueryModAudits func(childComplexity int, input ModAuditQueryInput) int QueryNotifications func(childComplexity int, input QueryNotificationsInput) int QueryPerformers func(childComplexity int, input PerformerQueryInput) int QueryScenes func(childComplexity int, input SceneQueryInput) int QuerySites func(childComplexity int) int QueryStudios func(childComplexity int, input StudioQueryInput) int QueryTagCategories func(childComplexity int) int QueryTags func(childComplexity int, input TagQueryInput) int QueryUsers func(childComplexity int, input UserQueryInput) int SearchPerformer func(childComplexity int, term string, limit *int) int SearchPerformers func(childComplexity int, term string, limit *int, page *int, perPage *int, filter *PerformerSearchFilter) int SearchScene func(childComplexity int, term string, limit *int) int SearchScenes func(childComplexity int, term string, limit *int, page *int, perPage *int) int SearchStudio func(childComplexity int, term string, limit *int) int SearchTag func(childComplexity int, term string, limit *int) int Version func(childComplexity int) int } QueryEditsResultType struct { Count func(childComplexity int) int Edits func(childComplexity int) int } QueryExistingPerformerResult struct { Edits func(childComplexity int) int Performers func(childComplexity int) int } QueryExistingSceneResult struct { Edits func(childComplexity int) int Scenes func(childComplexity int) int } QueryModAuditsResultType struct { Audits func(childComplexity int) int Count func(childComplexity int) int } QueryNotificationsResult struct { Count func(childComplexity int) int Notifications func(childComplexity int) int } QueryPerformersResultType struct { Count func(childComplexity int) int Facets func(childComplexity int) int Performers func(childComplexity int) int } QueryScenesResultType struct { Count func(childComplexity int) int Scenes func(childComplexity int) int } QuerySitesResultType struct { Count func(childComplexity int) int Sites func(childComplexity int) int } QueryStudiosResultType struct { Count func(childComplexity int) int Studios func(childComplexity int) int } QueryTagCategoriesResultType struct { Count func(childComplexity int) int TagCategories func(childComplexity int) int } QueryTagsResultType struct { Count func(childComplexity int) int Tags func(childComplexity int) int } QueryUsersResultType struct { Count func(childComplexity int) int Users func(childComplexity int) int } Scene struct { Code func(childComplexity int) int Created func(childComplexity int) int Date func(childComplexity int) int Deleted func(childComplexity int) int Details func(childComplexity int) int Director func(childComplexity int) int Duration func(childComplexity int) int Edits func(childComplexity int) int Fingerprints func(childComplexity int, isSubmitted *bool) int ID func(childComplexity int) int Images func(childComplexity int) int Performers func(childComplexity int) int ProductionDate func(childComplexity int) int ReleaseDate func(childComplexity int) int Studio func(childComplexity int) int Tags func(childComplexity int) int Title func(childComplexity int) int Updated func(childComplexity int) int Urls func(childComplexity int) int } SceneDraft struct { Code func(childComplexity int) int Date func(childComplexity int) int Details func(childComplexity int) int Director func(childComplexity int) int Fingerprints func(childComplexity int) int ID func(childComplexity int) int Image func(childComplexity int) int Performers func(childComplexity int) int ProductionDate func(childComplexity int) int Studio func(childComplexity int) int Tags func(childComplexity int) int Title func(childComplexity int) int URLs func(childComplexity int) int } SceneEdit struct { AddedFingerprints func(childComplexity int) int AddedImages func(childComplexity int) int AddedPerformers func(childComplexity int) int AddedTags func(childComplexity int) int AddedUrls func(childComplexity int) int Code func(childComplexity int) int Date func(childComplexity int) int Details func(childComplexity int) int Director func(childComplexity int) int DraftID func(childComplexity int) int Duration func(childComplexity int) int Fingerprints func(childComplexity int) int Images func(childComplexity int) int Performers func(childComplexity int) int ProductionDate func(childComplexity int) int RemovedFingerprints func(childComplexity int) int RemovedImages func(childComplexity int) int RemovedPerformers func(childComplexity int) int RemovedTags func(childComplexity int) int RemovedUrls func(childComplexity int) int Studio func(childComplexity int) int Tags func(childComplexity int) int Title func(childComplexity int) int Urls func(childComplexity int) int } Site struct { Created func(childComplexity int) int Description func(childComplexity int) int ID func(childComplexity int) int Icon func(childComplexity int) int Name func(childComplexity int) int Regex func(childComplexity int) int URL func(childComplexity int) int Updated func(childComplexity int) int ValidTypes func(childComplexity int) int } StashBoxConfig struct { EditUpdateLimit func(childComplexity int) int GuidelinesURL func(childComplexity int) int HostURL func(childComplexity int) int MinDestructiveVotingPeriod func(childComplexity int) int RequireActivation func(childComplexity int) int RequireInvite func(childComplexity int) int RequireSceneDraft func(childComplexity int) int RequireTagRole func(childComplexity int) int VoteApplicationThreshold func(childComplexity int) int VoteCronInterval func(childComplexity int) int VotePromotionThreshold func(childComplexity int) int VotingPeriod func(childComplexity int) int } Studio struct { Aliases func(childComplexity int) int ChildStudios func(childComplexity int) int Created func(childComplexity int) int Deleted func(childComplexity int) int ID func(childComplexity int) int Images func(childComplexity int) int IsFavorite func(childComplexity int) int Name func(childComplexity int) int Parent func(childComplexity int) int Performers func(childComplexity int, input PerformerQueryInput) int SubStudios func(childComplexity int, input *StudioQueryInput) int Updated func(childComplexity int) int Urls func(childComplexity int) int } StudioEdit struct { AddedAliases func(childComplexity int) int AddedImages func(childComplexity int) int AddedUrls func(childComplexity int) int Images func(childComplexity int) int Name func(childComplexity int) int Parent func(childComplexity int) int RemovedAliases func(childComplexity int) int RemovedImages func(childComplexity int) int RemovedUrls func(childComplexity int) int Urls func(childComplexity int) int } Tag struct { Aliases func(childComplexity int) int Category func(childComplexity int) int Created func(childComplexity int) int Deleted func(childComplexity int) int Description func(childComplexity int) int Edits func(childComplexity int) int ID func(childComplexity int) int Name func(childComplexity int) int Updated func(childComplexity int) int } TagCategory struct { Description func(childComplexity int) int Group func(childComplexity int) int ID func(childComplexity int) int Name func(childComplexity int) int } TagEdit struct { AddedAliases func(childComplexity int) int Aliases func(childComplexity int) int Category func(childComplexity int) int Description func(childComplexity int) int Name func(childComplexity int) int RemovedAliases func(childComplexity int) int } URL struct { Site func(childComplexity int) int Type func(childComplexity int) int URL func(childComplexity int) int } UpdatedEdit struct { Edit func(childComplexity int) int } User struct { APICalls func(childComplexity int) int APIKey func(childComplexity int) int ActiveInviteCodes func(childComplexity int) int EditCount func(childComplexity int) int Email func(childComplexity int) int ID func(childComplexity int) int InviteCodes func(childComplexity int) int InviteTokens func(childComplexity int) int InvitedBy func(childComplexity int) int Name func(childComplexity int) int NotificationSubscriptions func(childComplexity int) int Roles func(childComplexity int) int VoteCount func(childComplexity int) int } UserEditCount struct { Accepted func(childComplexity int) int Canceled func(childComplexity int) int Failed func(childComplexity int) int ImmediateAccepted func(childComplexity int) int ImmediateRejected func(childComplexity int) int Pending func(childComplexity int) int Rejected func(childComplexity int) int } UserVoteCount struct { Abstain func(childComplexity int) int Accept func(childComplexity int) int ImmediateAccept func(childComplexity int) int ImmediateReject func(childComplexity int) int Reject func(childComplexity int) int } Version struct { BuildTime func(childComplexity int) int BuildType func(childComplexity int) int Hash func(childComplexity int) int Version func(childComplexity int) int } } type DraftResolver interface { Created(ctx context.Context, obj *Draft) (*time.Time, error) Expires(ctx context.Context, obj *Draft) (*time.Time, error) Data(ctx context.Context, obj *Draft) (DraftData, error) } type EditResolver interface { User(ctx context.Context, obj *Edit) (*User, error) Target(ctx context.Context, obj *Edit) (EditTarget, error) TargetType(ctx context.Context, obj *Edit) (TargetTypeEnum, error) MergeSources(ctx context.Context, obj *Edit) ([]EditTarget, error) Operation(ctx context.Context, obj *Edit) (OperationEnum, error) Details(ctx context.Context, obj *Edit) (EditDetails, error) OldDetails(ctx context.Context, obj *Edit) (EditDetails, error) Options(ctx context.Context, obj *Edit) (*PerformerEditOptions, error) Comments(ctx context.Context, obj *Edit) ([]EditComment, error) Votes(ctx context.Context, obj *Edit) ([]EditVote, error) Destructive(ctx context.Context, obj *Edit) (bool, error) Status(ctx context.Context, obj *Edit) (VoteStatusEnum, error) Updatable(ctx context.Context, obj *Edit) (bool, error) Created(ctx context.Context, obj *Edit) (*time.Time, error) Updated(ctx context.Context, obj *Edit) (*time.Time, error) Closed(ctx context.Context, obj *Edit) (*time.Time, error) Expires(ctx context.Context, obj *Edit) (*time.Time, error) } type EditCommentResolver interface { User(ctx context.Context, obj *EditComment) (*User, error) Date(ctx context.Context, obj *EditComment) (*time.Time, error) Comment(ctx context.Context, obj *EditComment) (string, error) Edit(ctx context.Context, obj *EditComment) (*Edit, error) } type EditVoteResolver interface { User(ctx context.Context, obj *EditVote) (*User, error) Date(ctx context.Context, obj *EditVote) (*time.Time, error) Vote(ctx context.Context, obj *EditVote) (VoteTypeEnum, error) } type ImageResolver interface { URL(ctx context.Context, obj *Image) (string, error) } type ModAuditResolver interface { Action(ctx context.Context, obj *ModAudit) (ModAuditActionEnum, error) User(ctx context.Context, obj *ModAudit) (*User, error) } type MutationResolver interface { SceneCreate(ctx context.Context, input SceneCreateInput) (*Scene, error) SceneUpdate(ctx context.Context, input SceneUpdateInput) (*Scene, error) SceneDestroy(ctx context.Context, input SceneDestroyInput) (bool, error) PerformerCreate(ctx context.Context, input PerformerCreateInput) (*Performer, error) PerformerUpdate(ctx context.Context, input PerformerUpdateInput) (*Performer, error) PerformerDestroy(ctx context.Context, input PerformerDestroyInput) (bool, error) StudioCreate(ctx context.Context, input StudioCreateInput) (*Studio, error) StudioUpdate(ctx context.Context, input StudioUpdateInput) (*Studio, error) StudioDestroy(ctx context.Context, input StudioDestroyInput) (bool, error) TagCreate(ctx context.Context, input TagCreateInput) (*Tag, error) TagUpdate(ctx context.Context, input TagUpdateInput) (*Tag, error) TagDestroy(ctx context.Context, input TagDestroyInput) (bool, error) UserCreate(ctx context.Context, input UserCreateInput) (*User, error) UserUpdate(ctx context.Context, input UserUpdateInput) (*User, error) UserDestroy(ctx context.Context, input UserDestroyInput) (bool, error) ImageCreate(ctx context.Context, input ImageCreateInput) (*Image, error) ImageDestroy(ctx context.Context, input ImageDestroyInput) (bool, error) NewUser(ctx context.Context, input NewUserInput) (*uuid.UUID, error) ActivateNewUser(ctx context.Context, input ActivateNewUserInput) (*User, error) GenerateInviteCode(ctx context.Context) (*uuid.UUID, error) GenerateInviteCodes(ctx context.Context, input *GenerateInviteCodeInput) ([]uuid.UUID, error) RescindInviteCode(ctx context.Context, code uuid.UUID) (bool, error) GrantInvite(ctx context.Context, input GrantInviteInput) (int, error) RevokeInvite(ctx context.Context, input RevokeInviteInput) (int, error) TagCategoryCreate(ctx context.Context, input TagCategoryCreateInput) (*TagCategory, error) TagCategoryUpdate(ctx context.Context, input TagCategoryUpdateInput) (*TagCategory, error) TagCategoryDestroy(ctx context.Context, input TagCategoryDestroyInput) (bool, error) SiteCreate(ctx context.Context, input SiteCreateInput) (*Site, error) SiteUpdate(ctx context.Context, input SiteUpdateInput) (*Site, error) SiteDestroy(ctx context.Context, input SiteDestroyInput) (bool, error) RegenerateAPIKey(ctx context.Context, userID *uuid.UUID) (string, error) ResetPassword(ctx context.Context, input ResetPasswordInput) (bool, error) ChangePassword(ctx context.Context, input UserChangePasswordInput) (bool, error) RequestChangeEmail(ctx context.Context) (UserChangeEmailStatus, error) ValidateChangeEmail(ctx context.Context, token uuid.UUID, email string) (UserChangeEmailStatus, error) ConfirmChangeEmail(ctx context.Context, token uuid.UUID) (UserChangeEmailStatus, error) SceneEdit(ctx context.Context, input SceneEditInput) (*Edit, error) PerformerEdit(ctx context.Context, input PerformerEditInput) (*Edit, error) StudioEdit(ctx context.Context, input StudioEditInput) (*Edit, error) TagEdit(ctx context.Context, input TagEditInput) (*Edit, error) SceneEditUpdate(ctx context.Context, id uuid.UUID, input SceneEditInput) (*Edit, error) PerformerEditUpdate(ctx context.Context, id uuid.UUID, input PerformerEditInput) (*Edit, error) StudioEditUpdate(ctx context.Context, id uuid.UUID, input StudioEditInput) (*Edit, error) TagEditUpdate(ctx context.Context, id uuid.UUID, input TagEditInput) (*Edit, error) EditVote(ctx context.Context, input EditVoteInput) (*Edit, error) EditComment(ctx context.Context, input EditCommentInput) (*Edit, error) ApplyEdit(ctx context.Context, input ApplyEditInput) (*Edit, error) CancelEdit(ctx context.Context, input CancelEditInput) (*Edit, error) DeleteEdit(ctx context.Context, input DeleteEditInput) (bool, error) AmendEdit(ctx context.Context, input AmendEditInput) (*Edit, error) SubmitFingerprint(ctx context.Context, input FingerprintSubmission) (bool, error) SubmitFingerprints(ctx context.Context, input []FingerprintBatchSubmission) ([]FingerprintSubmissionResult, error) SceneMoveFingerprintSubmissions(ctx context.Context, input MoveFingerprintSubmissionsInput) (bool, error) SceneDeleteFingerprintSubmissions(ctx context.Context, input DeleteFingerprintSubmissionsInput) (bool, error) SubmitSceneDraft(ctx context.Context, input SceneDraftInput) (*DraftSubmissionStatus, error) SubmitPerformerDraft(ctx context.Context, input PerformerDraftInput) (*DraftSubmissionStatus, error) DestroyDraft(ctx context.Context, id uuid.UUID) (bool, error) FavoritePerformer(ctx context.Context, id uuid.UUID, favorite bool) (bool, error) FavoriteStudio(ctx context.Context, id uuid.UUID, favorite bool) (bool, error) MarkNotificationsRead(ctx context.Context, notification *MarkNotificationReadInput) (bool, error) UpdateNotificationSubscriptions(ctx context.Context, subscriptions []NotificationEnum) (bool, error) } type NotificationResolver interface { Created(ctx context.Context, obj *Notification) (*time.Time, error) Read(ctx context.Context, obj *Notification) (bool, error) Data(ctx context.Context, obj *Notification) (NotificationData, error) } type PerformerResolver interface { Aliases(ctx context.Context, obj *Performer) ([]string, error) Urls(ctx context.Context, obj *Performer) ([]URL, error) Birthdate(ctx context.Context, obj *Performer) (*FuzzyDate, error) Age(ctx context.Context, obj *Performer) (*int, error) Measurements(ctx context.Context, obj *Performer) (*Measurements, error) Tattoos(ctx context.Context, obj *Performer) ([]BodyModification, error) Piercings(ctx context.Context, obj *Performer) ([]BodyModification, error) Images(ctx context.Context, obj *Performer) ([]Image, error) Edits(ctx context.Context, obj *Performer) ([]Edit, error) SceneCount(ctx context.Context, obj *Performer) (int, error) Scenes(ctx context.Context, obj *Performer, input *PerformerScenesInput) ([]Scene, error) MergedIds(ctx context.Context, obj *Performer) ([]uuid.UUID, error) MergedIntoID(ctx context.Context, obj *Performer) (*uuid.UUID, error) Studios(ctx context.Context, obj *Performer, studioID *uuid.UUID) ([]PerformerStudio, error) IsFavorite(ctx context.Context, obj *Performer) (bool, error) } type PerformerDraftResolver interface { Image(ctx context.Context, obj *PerformerDraft) (*Image, error) } type PerformerEditResolver interface { Gender(ctx context.Context, obj *PerformerEdit) (*GenderEnum, error) Ethnicity(ctx context.Context, obj *PerformerEdit) (*EthnicityEnum, error) EyeColor(ctx context.Context, obj *PerformerEdit) (*EyeColorEnum, error) HairColor(ctx context.Context, obj *PerformerEdit) (*HairColorEnum, error) BreastType(ctx context.Context, obj *PerformerEdit) (*BreastTypeEnum, error) AddedImages(ctx context.Context, obj *PerformerEdit) ([]Image, error) RemovedImages(ctx context.Context, obj *PerformerEdit) ([]Image, error) Aliases(ctx context.Context, obj *PerformerEdit) ([]string, error) Urls(ctx context.Context, obj *PerformerEdit) ([]URL, error) Images(ctx context.Context, obj *PerformerEdit) ([]Image, error) Tattoos(ctx context.Context, obj *PerformerEdit) ([]BodyModification, error) Piercings(ctx context.Context, obj *PerformerEdit) ([]BodyModification, error) } type QueryResolver interface { FindPerformer(ctx context.Context, id uuid.UUID) (*Performer, error) QueryPerformers(ctx context.Context, input PerformerQueryInput) (*PerformerQuery, error) FindStudio(ctx context.Context, id *uuid.UUID, name *string) (*Studio, error) QueryStudios(ctx context.Context, input StudioQueryInput) (*QueryStudiosResultType, error) FindTag(ctx context.Context, id *uuid.UUID, name *string) (*Tag, error) FindTagOrAlias(ctx context.Context, name string) (*Tag, error) QueryTags(ctx context.Context, input TagQueryInput) (*QueryTagsResultType, error) FindTagCategory(ctx context.Context, id uuid.UUID) (*TagCategory, error) QueryTagCategories(ctx context.Context) (*QueryTagCategoriesResultType, error) FindScene(ctx context.Context, id uuid.UUID) (*Scene, error) FindScenesBySceneFingerprints(ctx context.Context, fingerprints [][]FingerprintQueryInput) ([][]*Scene, error) QueryScenes(ctx context.Context, input SceneQueryInput) (*SceneQuery, error) FindSite(ctx context.Context, id uuid.UUID) (*Site, error) QuerySites(ctx context.Context) (*QuerySitesResultType, error) FindEdit(ctx context.Context, id uuid.UUID) (*Edit, error) QueryEdits(ctx context.Context, input EditQueryInput) (*EditQuery, error) FindUser(ctx context.Context, id *uuid.UUID, username *string) (*User, error) QueryUsers(ctx context.Context, input UserQueryInput) (*QueryUsersResultType, error) Me(ctx context.Context) (*User, error) SearchPerformer(ctx context.Context, term string, limit *int) ([]Performer, error) SearchPerformers(ctx context.Context, term string, limit *int, page *int, perPage *int, filter *PerformerSearchFilter) (*PerformerQuery, error) SearchScene(ctx context.Context, term string, limit *int) ([]Scene, error) SearchScenes(ctx context.Context, term string, limit *int, page *int, perPage *int) (*SceneQuery, error) SearchTag(ctx context.Context, term string, limit *int) ([]Tag, error) SearchStudio(ctx context.Context, term string, limit *int) ([]Studio, error) FindDraft(ctx context.Context, id uuid.UUID) (*Draft, error) FindDrafts(ctx context.Context) ([]Draft, error) QueryExistingScene(ctx context.Context, input QueryExistingSceneInput) (*QueryExistingSceneResult, error) QueryExistingPerformer(ctx context.Context, input QueryExistingPerformerInput) (*QueryExistingPerformerResult, error) Version(ctx context.Context) (*Version, error) GetConfig(ctx context.Context) (*StashBoxConfig, error) QueryNotifications(ctx context.Context, input QueryNotificationsInput) (*QueryNotificationsResult, error) GetUnreadNotificationCount(ctx context.Context) (int, error) QueryModAudits(ctx context.Context, input ModAuditQueryInput) (*ModAuditQuery, error) } type QueryEditsResultTypeResolver interface { Count(ctx context.Context, obj *EditQuery) (int, error) Edits(ctx context.Context, obj *EditQuery) ([]Edit, error) } type QueryExistingPerformerResultResolver interface { Edits(ctx context.Context, obj *QueryExistingPerformerResult) ([]Edit, error) Performers(ctx context.Context, obj *QueryExistingPerformerResult) ([]Performer, error) } type QueryExistingSceneResultResolver interface { Edits(ctx context.Context, obj *QueryExistingSceneResult) ([]Edit, error) Scenes(ctx context.Context, obj *QueryExistingSceneResult) ([]Scene, error) } type QueryModAuditsResultTypeResolver interface { Count(ctx context.Context, obj *ModAuditQuery) (int, error) Audits(ctx context.Context, obj *ModAuditQuery) ([]ModAudit, error) } type QueryNotificationsResultResolver interface { Count(ctx context.Context, obj *QueryNotificationsResult) (int, error) Notifications(ctx context.Context, obj *QueryNotificationsResult) ([]Notification, error) } type QueryPerformersResultTypeResolver interface { Count(ctx context.Context, obj *PerformerQuery) (int, error) Performers(ctx context.Context, obj *PerformerQuery) ([]Performer, error) Facets(ctx context.Context, obj *PerformerQuery) (*PerformerSearchFacets, error) } type QueryScenesResultTypeResolver interface { Count(ctx context.Context, obj *SceneQuery) (int, error) Scenes(ctx context.Context, obj *SceneQuery) ([]Scene, error) } type SceneResolver interface { ReleaseDate(ctx context.Context, obj *Scene) (*string, error) Urls(ctx context.Context, obj *Scene) ([]URL, error) Studio(ctx context.Context, obj *Scene) (*Studio, error) Tags(ctx context.Context, obj *Scene) ([]Tag, error) Images(ctx context.Context, obj *Scene) ([]Image, error) Performers(ctx context.Context, obj *Scene) ([]PerformerAppearance, error) Fingerprints(ctx context.Context, obj *Scene, isSubmitted *bool) ([]Fingerprint, error) Edits(ctx context.Context, obj *Scene) ([]Edit, error) Created(ctx context.Context, obj *Scene) (*time.Time, error) Updated(ctx context.Context, obj *Scene) (*time.Time, error) } type SceneDraftResolver interface { Studio(ctx context.Context, obj *SceneDraft) (SceneDraftStudio, error) Performers(ctx context.Context, obj *SceneDraft) ([]SceneDraftPerformer, error) Tags(ctx context.Context, obj *SceneDraft) ([]SceneDraftTag, error) Image(ctx context.Context, obj *SceneDraft) (*Image, error) } type SceneEditResolver interface { Studio(ctx context.Context, obj *SceneEdit) (*Studio, error) AddedPerformers(ctx context.Context, obj *SceneEdit) ([]PerformerAppearance, error) RemovedPerformers(ctx context.Context, obj *SceneEdit) ([]PerformerAppearance, error) AddedTags(ctx context.Context, obj *SceneEdit) ([]Tag, error) RemovedTags(ctx context.Context, obj *SceneEdit) ([]Tag, error) AddedImages(ctx context.Context, obj *SceneEdit) ([]Image, error) RemovedImages(ctx context.Context, obj *SceneEdit) ([]Image, error) AddedFingerprints(ctx context.Context, obj *SceneEdit) ([]Fingerprint, error) RemovedFingerprints(ctx context.Context, obj *SceneEdit) ([]Fingerprint, error) Urls(ctx context.Context, obj *SceneEdit) ([]URL, error) Performers(ctx context.Context, obj *SceneEdit) ([]PerformerAppearance, error) Tags(ctx context.Context, obj *SceneEdit) ([]Tag, error) Images(ctx context.Context, obj *SceneEdit) ([]Image, error) Fingerprints(ctx context.Context, obj *SceneEdit) ([]Fingerprint, error) } type SiteResolver interface { ValidTypes(ctx context.Context, obj *Site) ([]ValidSiteTypeEnum, error) Icon(ctx context.Context, obj *Site) (string, error) Created(ctx context.Context, obj *Site) (*time.Time, error) Updated(ctx context.Context, obj *Site) (*time.Time, error) } type StudioResolver interface { Aliases(ctx context.Context, obj *Studio) ([]string, error) Urls(ctx context.Context, obj *Studio) ([]URL, error) Parent(ctx context.Context, obj *Studio) (*Studio, error) ChildStudios(ctx context.Context, obj *Studio) ([]Studio, error) SubStudios(ctx context.Context, obj *Studio, input *StudioQueryInput) (*QueryStudiosResultType, error) Images(ctx context.Context, obj *Studio) ([]Image, error) IsFavorite(ctx context.Context, obj *Studio) (bool, error) Created(ctx context.Context, obj *Studio) (*time.Time, error) Updated(ctx context.Context, obj *Studio) (*time.Time, error) Performers(ctx context.Context, obj *Studio, input PerformerQueryInput) (*PerformerQuery, error) } type StudioEditResolver interface { Parent(ctx context.Context, obj *StudioEdit) (*Studio, error) AddedImages(ctx context.Context, obj *StudioEdit) ([]Image, error) RemovedImages(ctx context.Context, obj *StudioEdit) ([]Image, error) Images(ctx context.Context, obj *StudioEdit) ([]Image, error) Urls(ctx context.Context, obj *StudioEdit) ([]URL, error) } type TagResolver interface { Aliases(ctx context.Context, obj *Tag) ([]string, error) Edits(ctx context.Context, obj *Tag) ([]Edit, error) Category(ctx context.Context, obj *Tag) (*TagCategory, error) } type TagCategoryResolver interface { Group(ctx context.Context, obj *TagCategory) (TagGroupEnum, error) } type TagEditResolver interface { Category(ctx context.Context, obj *TagEdit) (*TagCategory, error) Aliases(ctx context.Context, obj *TagEdit) ([]string, error) } type URLResolver interface { Type(ctx context.Context, obj *URL) (string, error) Site(ctx context.Context, obj *URL) (*Site, error) } type UserResolver interface { Roles(ctx context.Context, obj *User) ([]RoleEnum, error) NotificationSubscriptions(ctx context.Context, obj *User) ([]NotificationEnum, error) VoteCount(ctx context.Context, obj *User) (*UserVoteCount, error) EditCount(ctx context.Context, obj *User) (*UserEditCount, error) InvitedBy(ctx context.Context, obj *User) (*User, error) ActiveInviteCodes(ctx context.Context, obj *User) ([]string, error) InviteCodes(ctx context.Context, obj *User) ([]InviteKey, error) } type executableSchema graphql.ExecutableSchemaState[ResolverRoot, DirectiveRoot, ComplexityRoot] func (e *executableSchema) Schema() *ast.Schema { if e.SchemaData != nil { return e.SchemaData } return parsedSchema } func (e *executableSchema) Complexity(ctx context.Context, typeName, field string, childComplexity int, rawArgs map[string]any) (int, bool) { ec := newExecutionContext(nil, e, nil) _ = ec switch typeName + "." + field { case "BodyModification.description": if e.ComplexityRoot.BodyModification.Description == nil { break } return e.ComplexityRoot.BodyModification.Description(childComplexity), true case "BodyModification.location": if e.ComplexityRoot.BodyModification.Location == nil { break } return e.ComplexityRoot.BodyModification.Location(childComplexity), true case "CommentCommentedEdit.comment": if e.ComplexityRoot.CommentCommentedEdit.Comment == nil { break } return e.ComplexityRoot.CommentCommentedEdit.Comment(childComplexity), true case "CommentOwnEdit.comment": if e.ComplexityRoot.CommentOwnEdit.Comment == nil { break } return e.ComplexityRoot.CommentOwnEdit.Comment(childComplexity), true case "CommentVotedEdit.comment": if e.ComplexityRoot.CommentVotedEdit.Comment == nil { break } return e.ComplexityRoot.CommentVotedEdit.Comment(childComplexity), true case "DownvoteOwnEdit.edit": if e.ComplexityRoot.DownvoteOwnEdit.Edit == nil { break } return e.ComplexityRoot.DownvoteOwnEdit.Edit(childComplexity), true case "Draft.created": if e.ComplexityRoot.Draft.Created == nil { break } return e.ComplexityRoot.Draft.Created(childComplexity), true case "Draft.data": if e.ComplexityRoot.Draft.Data == nil { break } return e.ComplexityRoot.Draft.Data(childComplexity), true case "Draft.expires": if e.ComplexityRoot.Draft.Expires == nil { break } return e.ComplexityRoot.Draft.Expires(childComplexity), true case "Draft.id": if e.ComplexityRoot.Draft.ID == nil { break } return e.ComplexityRoot.Draft.ID(childComplexity), true case "DraftEntity.id": if e.ComplexityRoot.DraftEntity.ID == nil { break } return e.ComplexityRoot.DraftEntity.ID(childComplexity), true case "DraftEntity.name": if e.ComplexityRoot.DraftEntity.Name == nil { break } return e.ComplexityRoot.DraftEntity.Name(childComplexity), true case "DraftFingerprint.algorithm": if e.ComplexityRoot.DraftFingerprint.Algorithm == nil { break } return e.ComplexityRoot.DraftFingerprint.Algorithm(childComplexity), true case "DraftFingerprint.duration": if e.ComplexityRoot.DraftFingerprint.Duration == nil { break } return e.ComplexityRoot.DraftFingerprint.Duration(childComplexity), true case "DraftFingerprint.hash": if e.ComplexityRoot.DraftFingerprint.Hash == nil { break } return e.ComplexityRoot.DraftFingerprint.Hash(childComplexity), true case "DraftSubmissionStatus.id": if e.ComplexityRoot.DraftSubmissionStatus.ID == nil { break } return e.ComplexityRoot.DraftSubmissionStatus.ID(childComplexity), true case "Edit.applied": if e.ComplexityRoot.Edit.Applied == nil { break } return e.ComplexityRoot.Edit.Applied(childComplexity), true case "Edit.bot": if e.ComplexityRoot.Edit.Bot == nil { break } return e.ComplexityRoot.Edit.Bot(childComplexity), true case "Edit.closed": if e.ComplexityRoot.Edit.Closed == nil { break } return e.ComplexityRoot.Edit.Closed(childComplexity), true case "Edit.comments": if e.ComplexityRoot.Edit.Comments == nil { break } return e.ComplexityRoot.Edit.Comments(childComplexity), true case "Edit.created": if e.ComplexityRoot.Edit.Created == nil { break } return e.ComplexityRoot.Edit.Created(childComplexity), true case "Edit.destructive": if e.ComplexityRoot.Edit.Destructive == nil { break } return e.ComplexityRoot.Edit.Destructive(childComplexity), true case "Edit.details": if e.ComplexityRoot.Edit.Details == nil { break } return e.ComplexityRoot.Edit.Details(childComplexity), true case "Edit.expires": if e.ComplexityRoot.Edit.Expires == nil { break } return e.ComplexityRoot.Edit.Expires(childComplexity), true case "Edit.id": if e.ComplexityRoot.Edit.ID == nil { break } return e.ComplexityRoot.Edit.ID(childComplexity), true case "Edit.merge_sources": if e.ComplexityRoot.Edit.MergeSources == nil { break } return e.ComplexityRoot.Edit.MergeSources(childComplexity), true case "Edit.old_details": if e.ComplexityRoot.Edit.OldDetails == nil { break } return e.ComplexityRoot.Edit.OldDetails(childComplexity), true case "Edit.operation": if e.ComplexityRoot.Edit.Operation == nil { break } return e.ComplexityRoot.Edit.Operation(childComplexity), true case "Edit.options": if e.ComplexityRoot.Edit.Options == nil { break } return e.ComplexityRoot.Edit.Options(childComplexity), true case "Edit.status": if e.ComplexityRoot.Edit.Status == nil { break } return e.ComplexityRoot.Edit.Status(childComplexity), true case "Edit.target": if e.ComplexityRoot.Edit.Target == nil { break } return e.ComplexityRoot.Edit.Target(childComplexity), true case "Edit.target_type": if e.ComplexityRoot.Edit.TargetType == nil { break } return e.ComplexityRoot.Edit.TargetType(childComplexity), true case "Edit.updatable": if e.ComplexityRoot.Edit.Updatable == nil { break } return e.ComplexityRoot.Edit.Updatable(childComplexity), true case "Edit.update_count": if e.ComplexityRoot.Edit.UpdateCount == nil { break } return e.ComplexityRoot.Edit.UpdateCount(childComplexity), true case "Edit.updated": if e.ComplexityRoot.Edit.Updated == nil { break } return e.ComplexityRoot.Edit.Updated(childComplexity), true case "Edit.user": if e.ComplexityRoot.Edit.User == nil { break } return e.ComplexityRoot.Edit.User(childComplexity), true case "Edit.vote_count": if e.ComplexityRoot.Edit.VoteCount == nil { break } return e.ComplexityRoot.Edit.VoteCount(childComplexity), true case "Edit.votes": if e.ComplexityRoot.Edit.Votes == nil { break } return e.ComplexityRoot.Edit.Votes(childComplexity), true case "EditComment.comment": if e.ComplexityRoot.EditComment.Comment == nil { break } return e.ComplexityRoot.EditComment.Comment(childComplexity), true case "EditComment.date": if e.ComplexityRoot.EditComment.Date == nil { break } return e.ComplexityRoot.EditComment.Date(childComplexity), true case "EditComment.edit": if e.ComplexityRoot.EditComment.Edit == nil { break } return e.ComplexityRoot.EditComment.Edit(childComplexity), true case "EditComment.id": if e.ComplexityRoot.EditComment.ID == nil { break } return e.ComplexityRoot.EditComment.ID(childComplexity), true case "EditComment.user": if e.ComplexityRoot.EditComment.User == nil { break } return e.ComplexityRoot.EditComment.User(childComplexity), true case "EditVote.date": if e.ComplexityRoot.EditVote.Date == nil { break } return e.ComplexityRoot.EditVote.Date(childComplexity), true case "EditVote.user": if e.ComplexityRoot.EditVote.User == nil { break } return e.ComplexityRoot.EditVote.User(childComplexity), true case "EditVote.vote": if e.ComplexityRoot.EditVote.Vote == nil { break } return e.ComplexityRoot.EditVote.Vote(childComplexity), true case "FailedOwnEdit.edit": if e.ComplexityRoot.FailedOwnEdit.Edit == nil { break } return e.ComplexityRoot.FailedOwnEdit.Edit(childComplexity), true case "FavoritePerformerEdit.edit": if e.ComplexityRoot.FavoritePerformerEdit.Edit == nil { break } return e.ComplexityRoot.FavoritePerformerEdit.Edit(childComplexity), true case "FavoritePerformerScene.scene": if e.ComplexityRoot.FavoritePerformerScene.Scene == nil { break } return e.ComplexityRoot.FavoritePerformerScene.Scene(childComplexity), true case "FavoriteStudioEdit.edit": if e.ComplexityRoot.FavoriteStudioEdit.Edit == nil { break } return e.ComplexityRoot.FavoriteStudioEdit.Edit(childComplexity), true case "FavoriteStudioScene.scene": if e.ComplexityRoot.FavoriteStudioScene.Scene == nil { break } return e.ComplexityRoot.FavoriteStudioScene.Scene(childComplexity), true case "Fingerprint.algorithm": if e.ComplexityRoot.Fingerprint.Algorithm == nil { break } return e.ComplexityRoot.Fingerprint.Algorithm(childComplexity), true case "Fingerprint.created": if e.ComplexityRoot.Fingerprint.Created == nil { break } return e.ComplexityRoot.Fingerprint.Created(childComplexity), true case "Fingerprint.duration": if e.ComplexityRoot.Fingerprint.Duration == nil { break } return e.ComplexityRoot.Fingerprint.Duration(childComplexity), true case "Fingerprint.hash": if e.ComplexityRoot.Fingerprint.Hash == nil { break } return e.ComplexityRoot.Fingerprint.Hash(childComplexity), true case "Fingerprint.reports": if e.ComplexityRoot.Fingerprint.Reports == nil { break } return e.ComplexityRoot.Fingerprint.Reports(childComplexity), true case "Fingerprint.submissions": if e.ComplexityRoot.Fingerprint.Submissions == nil { break } return e.ComplexityRoot.Fingerprint.Submissions(childComplexity), true case "Fingerprint.updated": if e.ComplexityRoot.Fingerprint.Updated == nil { break } return e.ComplexityRoot.Fingerprint.Updated(childComplexity), true case "Fingerprint.user_reported": if e.ComplexityRoot.Fingerprint.UserReported == nil { break } return e.ComplexityRoot.Fingerprint.UserReported(childComplexity), true case "Fingerprint.user_submitted": if e.ComplexityRoot.Fingerprint.UserSubmitted == nil { break } return e.ComplexityRoot.Fingerprint.UserSubmitted(childComplexity), true case "FingerprintSubmissionResult.error": if e.ComplexityRoot.FingerprintSubmissionResult.Error == nil { break } return e.ComplexityRoot.FingerprintSubmissionResult.Error(childComplexity), true case "FingerprintSubmissionResult.hash": if e.ComplexityRoot.FingerprintSubmissionResult.Hash == nil { break } return e.ComplexityRoot.FingerprintSubmissionResult.Hash(childComplexity), true case "FingerprintSubmissionResult.scene_id": if e.ComplexityRoot.FingerprintSubmissionResult.SceneID == nil { break } return e.ComplexityRoot.FingerprintSubmissionResult.SceneID(childComplexity), true case "FingerprintedSceneEdit.edit": if e.ComplexityRoot.FingerprintedSceneEdit.Edit == nil { break } return e.ComplexityRoot.FingerprintedSceneEdit.Edit(childComplexity), true case "FuzzyDate.accuracy": if e.ComplexityRoot.FuzzyDate.Accuracy == nil { break } return e.ComplexityRoot.FuzzyDate.Accuracy(childComplexity), true case "FuzzyDate.date": if e.ComplexityRoot.FuzzyDate.Date == nil { break } return e.ComplexityRoot.FuzzyDate.Date(childComplexity), true case "GenderFacet.count": if e.ComplexityRoot.GenderFacet.Count == nil { break } return e.ComplexityRoot.GenderFacet.Count(childComplexity), true case "GenderFacet.gender": if e.ComplexityRoot.GenderFacet.Gender == nil { break } return e.ComplexityRoot.GenderFacet.Gender(childComplexity), true case "Image.height": if e.ComplexityRoot.Image.Height == nil { break } return e.ComplexityRoot.Image.Height(childComplexity), true case "Image.id": if e.ComplexityRoot.Image.ID == nil { break } return e.ComplexityRoot.Image.ID(childComplexity), true case "Image.url": if e.ComplexityRoot.Image.URL == nil { break } return e.ComplexityRoot.Image.URL(childComplexity), true case "Image.width": if e.ComplexityRoot.Image.Width == nil { break } return e.ComplexityRoot.Image.Width(childComplexity), true case "InviteKey.expires": if e.ComplexityRoot.InviteKey.Expires == nil { break } return e.ComplexityRoot.InviteKey.Expires(childComplexity), true case "InviteKey.id": if e.ComplexityRoot.InviteKey.ID == nil { break } return e.ComplexityRoot.InviteKey.ID(childComplexity), true case "InviteKey.uses": if e.ComplexityRoot.InviteKey.Uses == nil { break } return e.ComplexityRoot.InviteKey.Uses(childComplexity), true case "Measurements.band_size": if e.ComplexityRoot.Measurements.BandSize == nil { break } return e.ComplexityRoot.Measurements.BandSize(childComplexity), true case "Measurements.cup_size": if e.ComplexityRoot.Measurements.CupSize == nil { break } return e.ComplexityRoot.Measurements.CupSize(childComplexity), true case "Measurements.hip": if e.ComplexityRoot.Measurements.Hip == nil { break } return e.ComplexityRoot.Measurements.Hip(childComplexity), true case "Measurements.waist": if e.ComplexityRoot.Measurements.Waist == nil { break } return e.ComplexityRoot.Measurements.Waist(childComplexity), true case "ModAudit.action": if e.ComplexityRoot.ModAudit.Action == nil { break } return e.ComplexityRoot.ModAudit.Action(childComplexity), true case "ModAudit.created_at": if e.ComplexityRoot.ModAudit.CreatedAt == nil { break } return e.ComplexityRoot.ModAudit.CreatedAt(childComplexity), true case "ModAudit.data": if e.ComplexityRoot.ModAudit.Data == nil { break } return e.ComplexityRoot.ModAudit.Data(childComplexity), true case "ModAudit.id": if e.ComplexityRoot.ModAudit.ID == nil { break } return e.ComplexityRoot.ModAudit.ID(childComplexity), true case "ModAudit.reason": if e.ComplexityRoot.ModAudit.Reason == nil { break } return e.ComplexityRoot.ModAudit.Reason(childComplexity), true case "ModAudit.target_id": if e.ComplexityRoot.ModAudit.TargetID == nil { break } return e.ComplexityRoot.ModAudit.TargetID(childComplexity), true case "ModAudit.target_type": if e.ComplexityRoot.ModAudit.TargetType == nil { break } return e.ComplexityRoot.ModAudit.TargetType(childComplexity), true case "ModAudit.user": if e.ComplexityRoot.ModAudit.User == nil { break } return e.ComplexityRoot.ModAudit.User(childComplexity), true case "Mutation.activateNewUser": if e.ComplexityRoot.Mutation.ActivateNewUser == nil { break } args, err := ec.field_Mutation_activateNewUser_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.ActivateNewUser(childComplexity, args["input"].(ActivateNewUserInput)), true case "Mutation.amendEdit": if e.ComplexityRoot.Mutation.AmendEdit == nil { break } args, err := ec.field_Mutation_amendEdit_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.AmendEdit(childComplexity, args["input"].(AmendEditInput)), true case "Mutation.applyEdit": if e.ComplexityRoot.Mutation.ApplyEdit == nil { break } args, err := ec.field_Mutation_applyEdit_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.ApplyEdit(childComplexity, args["input"].(ApplyEditInput)), true case "Mutation.cancelEdit": if e.ComplexityRoot.Mutation.CancelEdit == nil { break } args, err := ec.field_Mutation_cancelEdit_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.CancelEdit(childComplexity, args["input"].(CancelEditInput)), true case "Mutation.changePassword": if e.ComplexityRoot.Mutation.ChangePassword == nil { break } args, err := ec.field_Mutation_changePassword_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.ChangePassword(childComplexity, args["input"].(UserChangePasswordInput)), true case "Mutation.confirmChangeEmail": if e.ComplexityRoot.Mutation.ConfirmChangeEmail == nil { break } args, err := ec.field_Mutation_confirmChangeEmail_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.ConfirmChangeEmail(childComplexity, args["token"].(uuid.UUID)), true case "Mutation.deleteEdit": if e.ComplexityRoot.Mutation.DeleteEdit == nil { break } args, err := ec.field_Mutation_deleteEdit_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.DeleteEdit(childComplexity, args["input"].(DeleteEditInput)), true case "Mutation.destroyDraft": if e.ComplexityRoot.Mutation.DestroyDraft == nil { break } args, err := ec.field_Mutation_destroyDraft_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.DestroyDraft(childComplexity, args["id"].(uuid.UUID)), true case "Mutation.editComment": if e.ComplexityRoot.Mutation.EditComment == nil { break } args, err := ec.field_Mutation_editComment_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.EditComment(childComplexity, args["input"].(EditCommentInput)), true case "Mutation.editVote": if e.ComplexityRoot.Mutation.EditVote == nil { break } args, err := ec.field_Mutation_editVote_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.EditVote(childComplexity, args["input"].(EditVoteInput)), true case "Mutation.favoritePerformer": if e.ComplexityRoot.Mutation.FavoritePerformer == nil { break } args, err := ec.field_Mutation_favoritePerformer_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.FavoritePerformer(childComplexity, args["id"].(uuid.UUID), args["favorite"].(bool)), true case "Mutation.favoriteStudio": if e.ComplexityRoot.Mutation.FavoriteStudio == nil { break } args, err := ec.field_Mutation_favoriteStudio_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.FavoriteStudio(childComplexity, args["id"].(uuid.UUID), args["favorite"].(bool)), true case "Mutation.generateInviteCode": if e.ComplexityRoot.Mutation.GenerateInviteCode == nil { break } return e.ComplexityRoot.Mutation.GenerateInviteCode(childComplexity), true case "Mutation.generateInviteCodes": if e.ComplexityRoot.Mutation.GenerateInviteCodes == nil { break } args, err := ec.field_Mutation_generateInviteCodes_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.GenerateInviteCodes(childComplexity, args["input"].(*GenerateInviteCodeInput)), true case "Mutation.grantInvite": if e.ComplexityRoot.Mutation.GrantInvite == nil { break } args, err := ec.field_Mutation_grantInvite_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.GrantInvite(childComplexity, args["input"].(GrantInviteInput)), true case "Mutation.imageCreate": if e.ComplexityRoot.Mutation.ImageCreate == nil { break } args, err := ec.field_Mutation_imageCreate_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.ImageCreate(childComplexity, args["input"].(ImageCreateInput)), true case "Mutation.imageDestroy": if e.ComplexityRoot.Mutation.ImageDestroy == nil { break } args, err := ec.field_Mutation_imageDestroy_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.ImageDestroy(childComplexity, args["input"].(ImageDestroyInput)), true case "Mutation.markNotificationsRead": if e.ComplexityRoot.Mutation.MarkNotificationsRead == nil { break } args, err := ec.field_Mutation_markNotificationsRead_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.MarkNotificationsRead(childComplexity, args["notification"].(*MarkNotificationReadInput)), true case "Mutation.newUser": if e.ComplexityRoot.Mutation.NewUser == nil { break } args, err := ec.field_Mutation_newUser_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.NewUser(childComplexity, args["input"].(NewUserInput)), true case "Mutation.performerCreate": if e.ComplexityRoot.Mutation.PerformerCreate == nil { break } args, err := ec.field_Mutation_performerCreate_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.PerformerCreate(childComplexity, args["input"].(PerformerCreateInput)), true case "Mutation.performerDestroy": if e.ComplexityRoot.Mutation.PerformerDestroy == nil { break } args, err := ec.field_Mutation_performerDestroy_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.PerformerDestroy(childComplexity, args["input"].(PerformerDestroyInput)), true case "Mutation.performerEdit": if e.ComplexityRoot.Mutation.PerformerEdit == nil { break } args, err := ec.field_Mutation_performerEdit_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.PerformerEdit(childComplexity, args["input"].(PerformerEditInput)), true case "Mutation.performerEditUpdate": if e.ComplexityRoot.Mutation.PerformerEditUpdate == nil { break } args, err := ec.field_Mutation_performerEditUpdate_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.PerformerEditUpdate(childComplexity, args["id"].(uuid.UUID), args["input"].(PerformerEditInput)), true case "Mutation.performerUpdate": if e.ComplexityRoot.Mutation.PerformerUpdate == nil { break } args, err := ec.field_Mutation_performerUpdate_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.PerformerUpdate(childComplexity, args["input"].(PerformerUpdateInput)), true case "Mutation.regenerateAPIKey": if e.ComplexityRoot.Mutation.RegenerateAPIKey == nil { break } args, err := ec.field_Mutation_regenerateAPIKey_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.RegenerateAPIKey(childComplexity, args["userID"].(*uuid.UUID)), true case "Mutation.requestChangeEmail": if e.ComplexityRoot.Mutation.RequestChangeEmail == nil { break } return e.ComplexityRoot.Mutation.RequestChangeEmail(childComplexity), true case "Mutation.rescindInviteCode": if e.ComplexityRoot.Mutation.RescindInviteCode == nil { break } args, err := ec.field_Mutation_rescindInviteCode_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.RescindInviteCode(childComplexity, args["code"].(uuid.UUID)), true case "Mutation.resetPassword": if e.ComplexityRoot.Mutation.ResetPassword == nil { break } args, err := ec.field_Mutation_resetPassword_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.ResetPassword(childComplexity, args["input"].(ResetPasswordInput)), true case "Mutation.revokeInvite": if e.ComplexityRoot.Mutation.RevokeInvite == nil { break } args, err := ec.field_Mutation_revokeInvite_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.RevokeInvite(childComplexity, args["input"].(RevokeInviteInput)), true case "Mutation.sceneCreate": if e.ComplexityRoot.Mutation.SceneCreate == nil { break } args, err := ec.field_Mutation_sceneCreate_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.SceneCreate(childComplexity, args["input"].(SceneCreateInput)), true case "Mutation.sceneDeleteFingerprintSubmissions": if e.ComplexityRoot.Mutation.SceneDeleteFingerprintSubmissions == nil { break } args, err := ec.field_Mutation_sceneDeleteFingerprintSubmissions_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.SceneDeleteFingerprintSubmissions(childComplexity, args["input"].(DeleteFingerprintSubmissionsInput)), true case "Mutation.sceneDestroy": if e.ComplexityRoot.Mutation.SceneDestroy == nil { break } args, err := ec.field_Mutation_sceneDestroy_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.SceneDestroy(childComplexity, args["input"].(SceneDestroyInput)), true case "Mutation.sceneEdit": if e.ComplexityRoot.Mutation.SceneEdit == nil { break } args, err := ec.field_Mutation_sceneEdit_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.SceneEdit(childComplexity, args["input"].(SceneEditInput)), true case "Mutation.sceneEditUpdate": if e.ComplexityRoot.Mutation.SceneEditUpdate == nil { break } args, err := ec.field_Mutation_sceneEditUpdate_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.SceneEditUpdate(childComplexity, args["id"].(uuid.UUID), args["input"].(SceneEditInput)), true case "Mutation.sceneMoveFingerprintSubmissions": if e.ComplexityRoot.Mutation.SceneMoveFingerprintSubmissions == nil { break } args, err := ec.field_Mutation_sceneMoveFingerprintSubmissions_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.SceneMoveFingerprintSubmissions(childComplexity, args["input"].(MoveFingerprintSubmissionsInput)), true case "Mutation.sceneUpdate": if e.ComplexityRoot.Mutation.SceneUpdate == nil { break } args, err := ec.field_Mutation_sceneUpdate_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.SceneUpdate(childComplexity, args["input"].(SceneUpdateInput)), true case "Mutation.siteCreate": if e.ComplexityRoot.Mutation.SiteCreate == nil { break } args, err := ec.field_Mutation_siteCreate_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.SiteCreate(childComplexity, args["input"].(SiteCreateInput)), true case "Mutation.siteDestroy": if e.ComplexityRoot.Mutation.SiteDestroy == nil { break } args, err := ec.field_Mutation_siteDestroy_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.SiteDestroy(childComplexity, args["input"].(SiteDestroyInput)), true case "Mutation.siteUpdate": if e.ComplexityRoot.Mutation.SiteUpdate == nil { break } args, err := ec.field_Mutation_siteUpdate_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.SiteUpdate(childComplexity, args["input"].(SiteUpdateInput)), true case "Mutation.studioCreate": if e.ComplexityRoot.Mutation.StudioCreate == nil { break } args, err := ec.field_Mutation_studioCreate_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.StudioCreate(childComplexity, args["input"].(StudioCreateInput)), true case "Mutation.studioDestroy": if e.ComplexityRoot.Mutation.StudioDestroy == nil { break } args, err := ec.field_Mutation_studioDestroy_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.StudioDestroy(childComplexity, args["input"].(StudioDestroyInput)), true case "Mutation.studioEdit": if e.ComplexityRoot.Mutation.StudioEdit == nil { break } args, err := ec.field_Mutation_studioEdit_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.StudioEdit(childComplexity, args["input"].(StudioEditInput)), true case "Mutation.studioEditUpdate": if e.ComplexityRoot.Mutation.StudioEditUpdate == nil { break } args, err := ec.field_Mutation_studioEditUpdate_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.StudioEditUpdate(childComplexity, args["id"].(uuid.UUID), args["input"].(StudioEditInput)), true case "Mutation.studioUpdate": if e.ComplexityRoot.Mutation.StudioUpdate == nil { break } args, err := ec.field_Mutation_studioUpdate_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.StudioUpdate(childComplexity, args["input"].(StudioUpdateInput)), true case "Mutation.submitFingerprint": if e.ComplexityRoot.Mutation.SubmitFingerprint == nil { break } args, err := ec.field_Mutation_submitFingerprint_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.SubmitFingerprint(childComplexity, args["input"].(FingerprintSubmission)), true case "Mutation.submitFingerprints": if e.ComplexityRoot.Mutation.SubmitFingerprints == nil { break } args, err := ec.field_Mutation_submitFingerprints_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.SubmitFingerprints(childComplexity, args["input"].([]FingerprintBatchSubmission)), true case "Mutation.submitPerformerDraft": if e.ComplexityRoot.Mutation.SubmitPerformerDraft == nil { break } args, err := ec.field_Mutation_submitPerformerDraft_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.SubmitPerformerDraft(childComplexity, args["input"].(PerformerDraftInput)), true case "Mutation.submitSceneDraft": if e.ComplexityRoot.Mutation.SubmitSceneDraft == nil { break } args, err := ec.field_Mutation_submitSceneDraft_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.SubmitSceneDraft(childComplexity, args["input"].(SceneDraftInput)), true case "Mutation.tagCategoryCreate": if e.ComplexityRoot.Mutation.TagCategoryCreate == nil { break } args, err := ec.field_Mutation_tagCategoryCreate_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.TagCategoryCreate(childComplexity, args["input"].(TagCategoryCreateInput)), true case "Mutation.tagCategoryDestroy": if e.ComplexityRoot.Mutation.TagCategoryDestroy == nil { break } args, err := ec.field_Mutation_tagCategoryDestroy_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.TagCategoryDestroy(childComplexity, args["input"].(TagCategoryDestroyInput)), true case "Mutation.tagCategoryUpdate": if e.ComplexityRoot.Mutation.TagCategoryUpdate == nil { break } args, err := ec.field_Mutation_tagCategoryUpdate_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.TagCategoryUpdate(childComplexity, args["input"].(TagCategoryUpdateInput)), true case "Mutation.tagCreate": if e.ComplexityRoot.Mutation.TagCreate == nil { break } args, err := ec.field_Mutation_tagCreate_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.TagCreate(childComplexity, args["input"].(TagCreateInput)), true case "Mutation.tagDestroy": if e.ComplexityRoot.Mutation.TagDestroy == nil { break } args, err := ec.field_Mutation_tagDestroy_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.TagDestroy(childComplexity, args["input"].(TagDestroyInput)), true case "Mutation.tagEdit": if e.ComplexityRoot.Mutation.TagEdit == nil { break } args, err := ec.field_Mutation_tagEdit_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.TagEdit(childComplexity, args["input"].(TagEditInput)), true case "Mutation.tagEditUpdate": if e.ComplexityRoot.Mutation.TagEditUpdate == nil { break } args, err := ec.field_Mutation_tagEditUpdate_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.TagEditUpdate(childComplexity, args["id"].(uuid.UUID), args["input"].(TagEditInput)), true case "Mutation.tagUpdate": if e.ComplexityRoot.Mutation.TagUpdate == nil { break } args, err := ec.field_Mutation_tagUpdate_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.TagUpdate(childComplexity, args["input"].(TagUpdateInput)), true case "Mutation.updateNotificationSubscriptions": if e.ComplexityRoot.Mutation.UpdateNotificationSubscriptions == nil { break } args, err := ec.field_Mutation_updateNotificationSubscriptions_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.UpdateNotificationSubscriptions(childComplexity, args["subscriptions"].([]NotificationEnum)), true case "Mutation.userCreate": if e.ComplexityRoot.Mutation.UserCreate == nil { break } args, err := ec.field_Mutation_userCreate_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.UserCreate(childComplexity, args["input"].(UserCreateInput)), true case "Mutation.userDestroy": if e.ComplexityRoot.Mutation.UserDestroy == nil { break } args, err := ec.field_Mutation_userDestroy_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.UserDestroy(childComplexity, args["input"].(UserDestroyInput)), true case "Mutation.userUpdate": if e.ComplexityRoot.Mutation.UserUpdate == nil { break } args, err := ec.field_Mutation_userUpdate_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.UserUpdate(childComplexity, args["input"].(UserUpdateInput)), true case "Mutation.validateChangeEmail": if e.ComplexityRoot.Mutation.ValidateChangeEmail == nil { break } args, err := ec.field_Mutation_validateChangeEmail_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Mutation.ValidateChangeEmail(childComplexity, args["token"].(uuid.UUID), args["email"].(string)), true case "Notification.created": if e.ComplexityRoot.Notification.Created == nil { break } return e.ComplexityRoot.Notification.Created(childComplexity), true case "Notification.data": if e.ComplexityRoot.Notification.Data == nil { break } return e.ComplexityRoot.Notification.Data(childComplexity), true case "Notification.read": if e.ComplexityRoot.Notification.Read == nil { break } return e.ComplexityRoot.Notification.Read(childComplexity), true case "Performer.age": if e.ComplexityRoot.Performer.Age == nil { break } return e.ComplexityRoot.Performer.Age(childComplexity), true case "Performer.aliases": if e.ComplexityRoot.Performer.Aliases == nil { break } return e.ComplexityRoot.Performer.Aliases(childComplexity), true case "Performer.band_size": if e.ComplexityRoot.Performer.BandSize == nil { break } return e.ComplexityRoot.Performer.BandSize(childComplexity), true case "Performer.birth_date": if e.ComplexityRoot.Performer.BirthDate == nil { break } return e.ComplexityRoot.Performer.BirthDate(childComplexity), true case "Performer.birthdate": if e.ComplexityRoot.Performer.Birthdate == nil { break } return e.ComplexityRoot.Performer.Birthdate(childComplexity), true case "Performer.breast_type": if e.ComplexityRoot.Performer.BreastType == nil { break } return e.ComplexityRoot.Performer.BreastType(childComplexity), true case "Performer.career_end_year": if e.ComplexityRoot.Performer.CareerEndYear == nil { break } return e.ComplexityRoot.Performer.CareerEndYear(childComplexity), true case "Performer.career_start_year": if e.ComplexityRoot.Performer.CareerStartYear == nil { break } return e.ComplexityRoot.Performer.CareerStartYear(childComplexity), true case "Performer.country": if e.ComplexityRoot.Performer.Country == nil { break } return e.ComplexityRoot.Performer.Country(childComplexity), true case "Performer.created": if e.ComplexityRoot.Performer.Created == nil { break } return e.ComplexityRoot.Performer.Created(childComplexity), true case "Performer.cup_size": if e.ComplexityRoot.Performer.CupSize == nil { break } return e.ComplexityRoot.Performer.CupSize(childComplexity), true case "Performer.death_date": if e.ComplexityRoot.Performer.DeathDate == nil { break } return e.ComplexityRoot.Performer.DeathDate(childComplexity), true case "Performer.deleted": if e.ComplexityRoot.Performer.Deleted == nil { break } return e.ComplexityRoot.Performer.Deleted(childComplexity), true case "Performer.disambiguation": if e.ComplexityRoot.Performer.Disambiguation == nil { break } return e.ComplexityRoot.Performer.Disambiguation(childComplexity), true case "Performer.edits": if e.ComplexityRoot.Performer.Edits == nil { break } return e.ComplexityRoot.Performer.Edits(childComplexity), true case "Performer.ethnicity": if e.ComplexityRoot.Performer.Ethnicity == nil { break } return e.ComplexityRoot.Performer.Ethnicity(childComplexity), true case "Performer.eye_color": if e.ComplexityRoot.Performer.EyeColor == nil { break } return e.ComplexityRoot.Performer.EyeColor(childComplexity), true case "Performer.gender": if e.ComplexityRoot.Performer.Gender == nil { break } return e.ComplexityRoot.Performer.Gender(childComplexity), true case "Performer.hair_color": if e.ComplexityRoot.Performer.HairColor == nil { break } return e.ComplexityRoot.Performer.HairColor(childComplexity), true case "Performer.height": if e.ComplexityRoot.Performer.Height == nil { break } return e.ComplexityRoot.Performer.Height(childComplexity), true case "Performer.hip_size": if e.ComplexityRoot.Performer.HipSize == nil { break } return e.ComplexityRoot.Performer.HipSize(childComplexity), true case "Performer.id": if e.ComplexityRoot.Performer.ID == nil { break } return e.ComplexityRoot.Performer.ID(childComplexity), true case "Performer.images": if e.ComplexityRoot.Performer.Images == nil { break } return e.ComplexityRoot.Performer.Images(childComplexity), true case "Performer.is_favorite": if e.ComplexityRoot.Performer.IsFavorite == nil { break } return e.ComplexityRoot.Performer.IsFavorite(childComplexity), true case "Performer.measurements": if e.ComplexityRoot.Performer.Measurements == nil { break } return e.ComplexityRoot.Performer.Measurements(childComplexity), true case "Performer.merged_ids": if e.ComplexityRoot.Performer.MergedIds == nil { break } return e.ComplexityRoot.Performer.MergedIds(childComplexity), true case "Performer.merged_into_id": if e.ComplexityRoot.Performer.MergedIntoID == nil { break } return e.ComplexityRoot.Performer.MergedIntoID(childComplexity), true case "Performer.name": if e.ComplexityRoot.Performer.Name == nil { break } return e.ComplexityRoot.Performer.Name(childComplexity), true case "Performer.piercings": if e.ComplexityRoot.Performer.Piercings == nil { break } return e.ComplexityRoot.Performer.Piercings(childComplexity), true case "Performer.scene_count": if e.ComplexityRoot.Performer.SceneCount == nil { break } return e.ComplexityRoot.Performer.SceneCount(childComplexity), true case "Performer.scenes": if e.ComplexityRoot.Performer.Scenes == nil { break } args, err := ec.field_Performer_scenes_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Performer.Scenes(childComplexity, args["input"].(*PerformerScenesInput)), true case "Performer.studios": if e.ComplexityRoot.Performer.Studios == nil { break } args, err := ec.field_Performer_studios_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Performer.Studios(childComplexity, args["studio_id"].(*uuid.UUID)), true case "Performer.tattoos": if e.ComplexityRoot.Performer.Tattoos == nil { break } return e.ComplexityRoot.Performer.Tattoos(childComplexity), true case "Performer.updated": if e.ComplexityRoot.Performer.Updated == nil { break } return e.ComplexityRoot.Performer.Updated(childComplexity), true case "Performer.urls": if e.ComplexityRoot.Performer.Urls == nil { break } return e.ComplexityRoot.Performer.Urls(childComplexity), true case "Performer.waist_size": if e.ComplexityRoot.Performer.WaistSize == nil { break } return e.ComplexityRoot.Performer.WaistSize(childComplexity), true case "PerformerAppearance.as": if e.ComplexityRoot.PerformerAppearance.As == nil { break } return e.ComplexityRoot.PerformerAppearance.As(childComplexity), true case "PerformerAppearance.performer": if e.ComplexityRoot.PerformerAppearance.Performer == nil { break } return e.ComplexityRoot.PerformerAppearance.Performer(childComplexity), true case "PerformerDraft.aliases": if e.ComplexityRoot.PerformerDraft.Aliases == nil { break } return e.ComplexityRoot.PerformerDraft.Aliases(childComplexity), true case "PerformerDraft.birthdate": if e.ComplexityRoot.PerformerDraft.Birthdate == nil { break } return e.ComplexityRoot.PerformerDraft.Birthdate(childComplexity), true case "PerformerDraft.breast_type": if e.ComplexityRoot.PerformerDraft.BreastType == nil { break } return e.ComplexityRoot.PerformerDraft.BreastType(childComplexity), true case "PerformerDraft.career_end_year": if e.ComplexityRoot.PerformerDraft.CareerEndYear == nil { break } return e.ComplexityRoot.PerformerDraft.CareerEndYear(childComplexity), true case "PerformerDraft.career_start_year": if e.ComplexityRoot.PerformerDraft.CareerStartYear == nil { break } return e.ComplexityRoot.PerformerDraft.CareerStartYear(childComplexity), true case "PerformerDraft.country": if e.ComplexityRoot.PerformerDraft.Country == nil { break } return e.ComplexityRoot.PerformerDraft.Country(childComplexity), true case "PerformerDraft.deathdate": if e.ComplexityRoot.PerformerDraft.Deathdate == nil { break } return e.ComplexityRoot.PerformerDraft.Deathdate(childComplexity), true case "PerformerDraft.disambiguation": if e.ComplexityRoot.PerformerDraft.Disambiguation == nil { break } return e.ComplexityRoot.PerformerDraft.Disambiguation(childComplexity), true case "PerformerDraft.ethnicity": if e.ComplexityRoot.PerformerDraft.Ethnicity == nil { break } return e.ComplexityRoot.PerformerDraft.Ethnicity(childComplexity), true case "PerformerDraft.eye_color": if e.ComplexityRoot.PerformerDraft.EyeColor == nil { break } return e.ComplexityRoot.PerformerDraft.EyeColor(childComplexity), true case "PerformerDraft.gender": if e.ComplexityRoot.PerformerDraft.Gender == nil { break } return e.ComplexityRoot.PerformerDraft.Gender(childComplexity), true case "PerformerDraft.hair_color": if e.ComplexityRoot.PerformerDraft.HairColor == nil { break } return e.ComplexityRoot.PerformerDraft.HairColor(childComplexity), true case "PerformerDraft.height": if e.ComplexityRoot.PerformerDraft.Height == nil { break } return e.ComplexityRoot.PerformerDraft.Height(childComplexity), true case "PerformerDraft.id": if e.ComplexityRoot.PerformerDraft.ID == nil { break } return e.ComplexityRoot.PerformerDraft.ID(childComplexity), true case "PerformerDraft.image": if e.ComplexityRoot.PerformerDraft.Image == nil { break } return e.ComplexityRoot.PerformerDraft.Image(childComplexity), true case "PerformerDraft.measurements": if e.ComplexityRoot.PerformerDraft.Measurements == nil { break } return e.ComplexityRoot.PerformerDraft.Measurements(childComplexity), true case "PerformerDraft.name": if e.ComplexityRoot.PerformerDraft.Name == nil { break } return e.ComplexityRoot.PerformerDraft.Name(childComplexity), true case "PerformerDraft.piercings": if e.ComplexityRoot.PerformerDraft.Piercings == nil { break } return e.ComplexityRoot.PerformerDraft.Piercings(childComplexity), true case "PerformerDraft.tattoos": if e.ComplexityRoot.PerformerDraft.Tattoos == nil { break } return e.ComplexityRoot.PerformerDraft.Tattoos(childComplexity), true case "PerformerDraft.urls": if e.ComplexityRoot.PerformerDraft.Urls == nil { break } return e.ComplexityRoot.PerformerDraft.Urls(childComplexity), true case "PerformerEdit.added_aliases": if e.ComplexityRoot.PerformerEdit.AddedAliases == nil { break } return e.ComplexityRoot.PerformerEdit.AddedAliases(childComplexity), true case "PerformerEdit.added_images": if e.ComplexityRoot.PerformerEdit.AddedImages == nil { break } return e.ComplexityRoot.PerformerEdit.AddedImages(childComplexity), true case "PerformerEdit.added_piercings": if e.ComplexityRoot.PerformerEdit.AddedPiercings == nil { break } return e.ComplexityRoot.PerformerEdit.AddedPiercings(childComplexity), true case "PerformerEdit.added_tattoos": if e.ComplexityRoot.PerformerEdit.AddedTattoos == nil { break } return e.ComplexityRoot.PerformerEdit.AddedTattoos(childComplexity), true case "PerformerEdit.added_urls": if e.ComplexityRoot.PerformerEdit.AddedUrls == nil { break } return e.ComplexityRoot.PerformerEdit.AddedUrls(childComplexity), true case "PerformerEdit.aliases": if e.ComplexityRoot.PerformerEdit.Aliases == nil { break } return e.ComplexityRoot.PerformerEdit.Aliases(childComplexity), true case "PerformerEdit.band_size": if e.ComplexityRoot.PerformerEdit.BandSize == nil { break } return e.ComplexityRoot.PerformerEdit.BandSize(childComplexity), true case "PerformerEdit.birthdate": if e.ComplexityRoot.PerformerEdit.Birthdate == nil { break } return e.ComplexityRoot.PerformerEdit.Birthdate(childComplexity), true case "PerformerEdit.breast_type": if e.ComplexityRoot.PerformerEdit.BreastType == nil { break } return e.ComplexityRoot.PerformerEdit.BreastType(childComplexity), true case "PerformerEdit.career_end_year": if e.ComplexityRoot.PerformerEdit.CareerEndYear == nil { break } return e.ComplexityRoot.PerformerEdit.CareerEndYear(childComplexity), true case "PerformerEdit.career_start_year": if e.ComplexityRoot.PerformerEdit.CareerStartYear == nil { break } return e.ComplexityRoot.PerformerEdit.CareerStartYear(childComplexity), true case "PerformerEdit.country": if e.ComplexityRoot.PerformerEdit.Country == nil { break } return e.ComplexityRoot.PerformerEdit.Country(childComplexity), true case "PerformerEdit.cup_size": if e.ComplexityRoot.PerformerEdit.CupSize == nil { break } return e.ComplexityRoot.PerformerEdit.CupSize(childComplexity), true case "PerformerEdit.deathdate": if e.ComplexityRoot.PerformerEdit.Deathdate == nil { break } return e.ComplexityRoot.PerformerEdit.Deathdate(childComplexity), true case "PerformerEdit.disambiguation": if e.ComplexityRoot.PerformerEdit.Disambiguation == nil { break } return e.ComplexityRoot.PerformerEdit.Disambiguation(childComplexity), true case "PerformerEdit.draft_id": if e.ComplexityRoot.PerformerEdit.DraftID == nil { break } return e.ComplexityRoot.PerformerEdit.DraftID(childComplexity), true case "PerformerEdit.ethnicity": if e.ComplexityRoot.PerformerEdit.Ethnicity == nil { break } return e.ComplexityRoot.PerformerEdit.Ethnicity(childComplexity), true case "PerformerEdit.eye_color": if e.ComplexityRoot.PerformerEdit.EyeColor == nil { break } return e.ComplexityRoot.PerformerEdit.EyeColor(childComplexity), true case "PerformerEdit.gender": if e.ComplexityRoot.PerformerEdit.Gender == nil { break } return e.ComplexityRoot.PerformerEdit.Gender(childComplexity), true case "PerformerEdit.hair_color": if e.ComplexityRoot.PerformerEdit.HairColor == nil { break } return e.ComplexityRoot.PerformerEdit.HairColor(childComplexity), true case "PerformerEdit.height": if e.ComplexityRoot.PerformerEdit.Height == nil { break } return e.ComplexityRoot.PerformerEdit.Height(childComplexity), true case "PerformerEdit.hip_size": if e.ComplexityRoot.PerformerEdit.HipSize == nil { break } return e.ComplexityRoot.PerformerEdit.HipSize(childComplexity), true case "PerformerEdit.images": if e.ComplexityRoot.PerformerEdit.Images == nil { break } return e.ComplexityRoot.PerformerEdit.Images(childComplexity), true case "PerformerEdit.name": if e.ComplexityRoot.PerformerEdit.Name == nil { break } return e.ComplexityRoot.PerformerEdit.Name(childComplexity), true case "PerformerEdit.piercings": if e.ComplexityRoot.PerformerEdit.Piercings == nil { break } return e.ComplexityRoot.PerformerEdit.Piercings(childComplexity), true case "PerformerEdit.removed_aliases": if e.ComplexityRoot.PerformerEdit.RemovedAliases == nil { break } return e.ComplexityRoot.PerformerEdit.RemovedAliases(childComplexity), true case "PerformerEdit.removed_images": if e.ComplexityRoot.PerformerEdit.RemovedImages == nil { break } return e.ComplexityRoot.PerformerEdit.RemovedImages(childComplexity), true case "PerformerEdit.removed_piercings": if e.ComplexityRoot.PerformerEdit.RemovedPiercings == nil { break } return e.ComplexityRoot.PerformerEdit.RemovedPiercings(childComplexity), true case "PerformerEdit.removed_tattoos": if e.ComplexityRoot.PerformerEdit.RemovedTattoos == nil { break } return e.ComplexityRoot.PerformerEdit.RemovedTattoos(childComplexity), true case "PerformerEdit.removed_urls": if e.ComplexityRoot.PerformerEdit.RemovedUrls == nil { break } return e.ComplexityRoot.PerformerEdit.RemovedUrls(childComplexity), true case "PerformerEdit.tattoos": if e.ComplexityRoot.PerformerEdit.Tattoos == nil { break } return e.ComplexityRoot.PerformerEdit.Tattoos(childComplexity), true case "PerformerEdit.urls": if e.ComplexityRoot.PerformerEdit.Urls == nil { break } return e.ComplexityRoot.PerformerEdit.Urls(childComplexity), true case "PerformerEdit.waist_size": if e.ComplexityRoot.PerformerEdit.WaistSize == nil { break } return e.ComplexityRoot.PerformerEdit.WaistSize(childComplexity), true case "PerformerEditOptions.set_merge_aliases": if e.ComplexityRoot.PerformerEditOptions.SetMergeAliases == nil { break } return e.ComplexityRoot.PerformerEditOptions.SetMergeAliases(childComplexity), true case "PerformerEditOptions.set_modify_aliases": if e.ComplexityRoot.PerformerEditOptions.SetModifyAliases == nil { break } return e.ComplexityRoot.PerformerEditOptions.SetModifyAliases(childComplexity), true case "PerformerSearchFacets.genders": if e.ComplexityRoot.PerformerSearchFacets.Genders == nil { break } return e.ComplexityRoot.PerformerSearchFacets.Genders(childComplexity), true case "PerformerStudio.scene_count": if e.ComplexityRoot.PerformerStudio.SceneCount == nil { break } return e.ComplexityRoot.PerformerStudio.SceneCount(childComplexity), true case "PerformerStudio.studio": if e.ComplexityRoot.PerformerStudio.Studio == nil { break } return e.ComplexityRoot.PerformerStudio.Studio(childComplexity), true case "Query.findDraft": if e.ComplexityRoot.Query.FindDraft == nil { break } args, err := ec.field_Query_findDraft_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Query.FindDraft(childComplexity, args["id"].(uuid.UUID)), true case "Query.findDrafts": if e.ComplexityRoot.Query.FindDrafts == nil { break } return e.ComplexityRoot.Query.FindDrafts(childComplexity), true case "Query.findEdit": if e.ComplexityRoot.Query.FindEdit == nil { break } args, err := ec.field_Query_findEdit_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Query.FindEdit(childComplexity, args["id"].(uuid.UUID)), true case "Query.findPerformer": if e.ComplexityRoot.Query.FindPerformer == nil { break } args, err := ec.field_Query_findPerformer_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Query.FindPerformer(childComplexity, args["id"].(uuid.UUID)), true case "Query.findScene": if e.ComplexityRoot.Query.FindScene == nil { break } args, err := ec.field_Query_findScene_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Query.FindScene(childComplexity, args["id"].(uuid.UUID)), true case "Query.findScenesBySceneFingerprints": if e.ComplexityRoot.Query.FindScenesBySceneFingerprints == nil { break } args, err := ec.field_Query_findScenesBySceneFingerprints_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Query.FindScenesBySceneFingerprints(childComplexity, args["fingerprints"].([][]FingerprintQueryInput)), true case "Query.findSite": if e.ComplexityRoot.Query.FindSite == nil { break } args, err := ec.field_Query_findSite_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Query.FindSite(childComplexity, args["id"].(uuid.UUID)), true case "Query.findStudio": if e.ComplexityRoot.Query.FindStudio == nil { break } args, err := ec.field_Query_findStudio_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Query.FindStudio(childComplexity, args["id"].(*uuid.UUID), args["name"].(*string)), true case "Query.findTag": if e.ComplexityRoot.Query.FindTag == nil { break } args, err := ec.field_Query_findTag_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Query.FindTag(childComplexity, args["id"].(*uuid.UUID), args["name"].(*string)), true case "Query.findTagCategory": if e.ComplexityRoot.Query.FindTagCategory == nil { break } args, err := ec.field_Query_findTagCategory_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Query.FindTagCategory(childComplexity, args["id"].(uuid.UUID)), true case "Query.findTagOrAlias": if e.ComplexityRoot.Query.FindTagOrAlias == nil { break } args, err := ec.field_Query_findTagOrAlias_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Query.FindTagOrAlias(childComplexity, args["name"].(string)), true case "Query.findUser": if e.ComplexityRoot.Query.FindUser == nil { break } args, err := ec.field_Query_findUser_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Query.FindUser(childComplexity, args["id"].(*uuid.UUID), args["username"].(*string)), true case "Query.getConfig": if e.ComplexityRoot.Query.GetConfig == nil { break } return e.ComplexityRoot.Query.GetConfig(childComplexity), true case "Query.getUnreadNotificationCount": if e.ComplexityRoot.Query.GetUnreadNotificationCount == nil { break } return e.ComplexityRoot.Query.GetUnreadNotificationCount(childComplexity), true case "Query.me": if e.ComplexityRoot.Query.Me == nil { break } return e.ComplexityRoot.Query.Me(childComplexity), true case "Query.queryEdits": if e.ComplexityRoot.Query.QueryEdits == nil { break } args, err := ec.field_Query_queryEdits_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Query.QueryEdits(childComplexity, args["input"].(EditQueryInput)), true case "Query.queryExistingPerformer": if e.ComplexityRoot.Query.QueryExistingPerformer == nil { break } args, err := ec.field_Query_queryExistingPerformer_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Query.QueryExistingPerformer(childComplexity, args["input"].(QueryExistingPerformerInput)), true case "Query.queryExistingScene": if e.ComplexityRoot.Query.QueryExistingScene == nil { break } args, err := ec.field_Query_queryExistingScene_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Query.QueryExistingScene(childComplexity, args["input"].(QueryExistingSceneInput)), true case "Query.queryModAudits": if e.ComplexityRoot.Query.QueryModAudits == nil { break } args, err := ec.field_Query_queryModAudits_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Query.QueryModAudits(childComplexity, args["input"].(ModAuditQueryInput)), true case "Query.queryNotifications": if e.ComplexityRoot.Query.QueryNotifications == nil { break } args, err := ec.field_Query_queryNotifications_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Query.QueryNotifications(childComplexity, args["input"].(QueryNotificationsInput)), true case "Query.queryPerformers": if e.ComplexityRoot.Query.QueryPerformers == nil { break } args, err := ec.field_Query_queryPerformers_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Query.QueryPerformers(childComplexity, args["input"].(PerformerQueryInput)), true case "Query.queryScenes": if e.ComplexityRoot.Query.QueryScenes == nil { break } args, err := ec.field_Query_queryScenes_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Query.QueryScenes(childComplexity, args["input"].(SceneQueryInput)), true case "Query.querySites": if e.ComplexityRoot.Query.QuerySites == nil { break } return e.ComplexityRoot.Query.QuerySites(childComplexity), true case "Query.queryStudios": if e.ComplexityRoot.Query.QueryStudios == nil { break } args, err := ec.field_Query_queryStudios_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Query.QueryStudios(childComplexity, args["input"].(StudioQueryInput)), true case "Query.queryTagCategories": if e.ComplexityRoot.Query.QueryTagCategories == nil { break } return e.ComplexityRoot.Query.QueryTagCategories(childComplexity), true case "Query.queryTags": if e.ComplexityRoot.Query.QueryTags == nil { break } args, err := ec.field_Query_queryTags_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Query.QueryTags(childComplexity, args["input"].(TagQueryInput)), true case "Query.queryUsers": if e.ComplexityRoot.Query.QueryUsers == nil { break } args, err := ec.field_Query_queryUsers_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Query.QueryUsers(childComplexity, args["input"].(UserQueryInput)), true case "Query.searchPerformer": if e.ComplexityRoot.Query.SearchPerformer == nil { break } args, err := ec.field_Query_searchPerformer_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Query.SearchPerformer(childComplexity, args["term"].(string), args["limit"].(*int)), true case "Query.searchPerformers": if e.ComplexityRoot.Query.SearchPerformers == nil { break } args, err := ec.field_Query_searchPerformers_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Query.SearchPerformers(childComplexity, args["term"].(string), args["limit"].(*int), args["page"].(*int), args["per_page"].(*int), args["filter"].(*PerformerSearchFilter)), true case "Query.searchScene": if e.ComplexityRoot.Query.SearchScene == nil { break } args, err := ec.field_Query_searchScene_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Query.SearchScene(childComplexity, args["term"].(string), args["limit"].(*int)), true case "Query.searchScenes": if e.ComplexityRoot.Query.SearchScenes == nil { break } args, err := ec.field_Query_searchScenes_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Query.SearchScenes(childComplexity, args["term"].(string), args["limit"].(*int), args["page"].(*int), args["per_page"].(*int)), true case "Query.searchStudio": if e.ComplexityRoot.Query.SearchStudio == nil { break } args, err := ec.field_Query_searchStudio_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Query.SearchStudio(childComplexity, args["term"].(string), args["limit"].(*int)), true case "Query.searchTag": if e.ComplexityRoot.Query.SearchTag == nil { break } args, err := ec.field_Query_searchTag_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Query.SearchTag(childComplexity, args["term"].(string), args["limit"].(*int)), true case "Query.version": if e.ComplexityRoot.Query.Version == nil { break } return e.ComplexityRoot.Query.Version(childComplexity), true case "QueryEditsResultType.count": if e.ComplexityRoot.QueryEditsResultType.Count == nil { break } return e.ComplexityRoot.QueryEditsResultType.Count(childComplexity), true case "QueryEditsResultType.edits": if e.ComplexityRoot.QueryEditsResultType.Edits == nil { break } return e.ComplexityRoot.QueryEditsResultType.Edits(childComplexity), true case "QueryExistingPerformerResult.edits": if e.ComplexityRoot.QueryExistingPerformerResult.Edits == nil { break } return e.ComplexityRoot.QueryExistingPerformerResult.Edits(childComplexity), true case "QueryExistingPerformerResult.performers": if e.ComplexityRoot.QueryExistingPerformerResult.Performers == nil { break } return e.ComplexityRoot.QueryExistingPerformerResult.Performers(childComplexity), true case "QueryExistingSceneResult.edits": if e.ComplexityRoot.QueryExistingSceneResult.Edits == nil { break } return e.ComplexityRoot.QueryExistingSceneResult.Edits(childComplexity), true case "QueryExistingSceneResult.scenes": if e.ComplexityRoot.QueryExistingSceneResult.Scenes == nil { break } return e.ComplexityRoot.QueryExistingSceneResult.Scenes(childComplexity), true case "QueryModAuditsResultType.audits": if e.ComplexityRoot.QueryModAuditsResultType.Audits == nil { break } return e.ComplexityRoot.QueryModAuditsResultType.Audits(childComplexity), true case "QueryModAuditsResultType.count": if e.ComplexityRoot.QueryModAuditsResultType.Count == nil { break } return e.ComplexityRoot.QueryModAuditsResultType.Count(childComplexity), true case "QueryNotificationsResult.count": if e.ComplexityRoot.QueryNotificationsResult.Count == nil { break } return e.ComplexityRoot.QueryNotificationsResult.Count(childComplexity), true case "QueryNotificationsResult.notifications": if e.ComplexityRoot.QueryNotificationsResult.Notifications == nil { break } return e.ComplexityRoot.QueryNotificationsResult.Notifications(childComplexity), true case "QueryPerformersResultType.count": if e.ComplexityRoot.QueryPerformersResultType.Count == nil { break } return e.ComplexityRoot.QueryPerformersResultType.Count(childComplexity), true case "QueryPerformersResultType.facets": if e.ComplexityRoot.QueryPerformersResultType.Facets == nil { break } return e.ComplexityRoot.QueryPerformersResultType.Facets(childComplexity), true case "QueryPerformersResultType.performers": if e.ComplexityRoot.QueryPerformersResultType.Performers == nil { break } return e.ComplexityRoot.QueryPerformersResultType.Performers(childComplexity), true case "QueryScenesResultType.count": if e.ComplexityRoot.QueryScenesResultType.Count == nil { break } return e.ComplexityRoot.QueryScenesResultType.Count(childComplexity), true case "QueryScenesResultType.scenes": if e.ComplexityRoot.QueryScenesResultType.Scenes == nil { break } return e.ComplexityRoot.QueryScenesResultType.Scenes(childComplexity), true case "QuerySitesResultType.count": if e.ComplexityRoot.QuerySitesResultType.Count == nil { break } return e.ComplexityRoot.QuerySitesResultType.Count(childComplexity), true case "QuerySitesResultType.sites": if e.ComplexityRoot.QuerySitesResultType.Sites == nil { break } return e.ComplexityRoot.QuerySitesResultType.Sites(childComplexity), true case "QueryStudiosResultType.count": if e.ComplexityRoot.QueryStudiosResultType.Count == nil { break } return e.ComplexityRoot.QueryStudiosResultType.Count(childComplexity), true case "QueryStudiosResultType.studios": if e.ComplexityRoot.QueryStudiosResultType.Studios == nil { break } return e.ComplexityRoot.QueryStudiosResultType.Studios(childComplexity), true case "QueryTagCategoriesResultType.count": if e.ComplexityRoot.QueryTagCategoriesResultType.Count == nil { break } return e.ComplexityRoot.QueryTagCategoriesResultType.Count(childComplexity), true case "QueryTagCategoriesResultType.tag_categories": if e.ComplexityRoot.QueryTagCategoriesResultType.TagCategories == nil { break } return e.ComplexityRoot.QueryTagCategoriesResultType.TagCategories(childComplexity), true case "QueryTagsResultType.count": if e.ComplexityRoot.QueryTagsResultType.Count == nil { break } return e.ComplexityRoot.QueryTagsResultType.Count(childComplexity), true case "QueryTagsResultType.tags": if e.ComplexityRoot.QueryTagsResultType.Tags == nil { break } return e.ComplexityRoot.QueryTagsResultType.Tags(childComplexity), true case "QueryUsersResultType.count": if e.ComplexityRoot.QueryUsersResultType.Count == nil { break } return e.ComplexityRoot.QueryUsersResultType.Count(childComplexity), true case "QueryUsersResultType.users": if e.ComplexityRoot.QueryUsersResultType.Users == nil { break } return e.ComplexityRoot.QueryUsersResultType.Users(childComplexity), true case "Scene.code": if e.ComplexityRoot.Scene.Code == nil { break } return e.ComplexityRoot.Scene.Code(childComplexity), true case "Scene.created": if e.ComplexityRoot.Scene.Created == nil { break } return e.ComplexityRoot.Scene.Created(childComplexity), true case "Scene.date": if e.ComplexityRoot.Scene.Date == nil { break } return e.ComplexityRoot.Scene.Date(childComplexity), true case "Scene.deleted": if e.ComplexityRoot.Scene.Deleted == nil { break } return e.ComplexityRoot.Scene.Deleted(childComplexity), true case "Scene.details": if e.ComplexityRoot.Scene.Details == nil { break } return e.ComplexityRoot.Scene.Details(childComplexity), true case "Scene.director": if e.ComplexityRoot.Scene.Director == nil { break } return e.ComplexityRoot.Scene.Director(childComplexity), true case "Scene.duration": if e.ComplexityRoot.Scene.Duration == nil { break } return e.ComplexityRoot.Scene.Duration(childComplexity), true case "Scene.edits": if e.ComplexityRoot.Scene.Edits == nil { break } return e.ComplexityRoot.Scene.Edits(childComplexity), true case "Scene.fingerprints": if e.ComplexityRoot.Scene.Fingerprints == nil { break } args, err := ec.field_Scene_fingerprints_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Scene.Fingerprints(childComplexity, args["is_submitted"].(*bool)), true case "Scene.id": if e.ComplexityRoot.Scene.ID == nil { break } return e.ComplexityRoot.Scene.ID(childComplexity), true case "Scene.images": if e.ComplexityRoot.Scene.Images == nil { break } return e.ComplexityRoot.Scene.Images(childComplexity), true case "Scene.performers": if e.ComplexityRoot.Scene.Performers == nil { break } return e.ComplexityRoot.Scene.Performers(childComplexity), true case "Scene.production_date": if e.ComplexityRoot.Scene.ProductionDate == nil { break } return e.ComplexityRoot.Scene.ProductionDate(childComplexity), true case "Scene.release_date": if e.ComplexityRoot.Scene.ReleaseDate == nil { break } return e.ComplexityRoot.Scene.ReleaseDate(childComplexity), true case "Scene.studio": if e.ComplexityRoot.Scene.Studio == nil { break } return e.ComplexityRoot.Scene.Studio(childComplexity), true case "Scene.tags": if e.ComplexityRoot.Scene.Tags == nil { break } return e.ComplexityRoot.Scene.Tags(childComplexity), true case "Scene.title": if e.ComplexityRoot.Scene.Title == nil { break } return e.ComplexityRoot.Scene.Title(childComplexity), true case "Scene.updated": if e.ComplexityRoot.Scene.Updated == nil { break } return e.ComplexityRoot.Scene.Updated(childComplexity), true case "Scene.urls": if e.ComplexityRoot.Scene.Urls == nil { break } return e.ComplexityRoot.Scene.Urls(childComplexity), true case "SceneDraft.code": if e.ComplexityRoot.SceneDraft.Code == nil { break } return e.ComplexityRoot.SceneDraft.Code(childComplexity), true case "SceneDraft.date": if e.ComplexityRoot.SceneDraft.Date == nil { break } return e.ComplexityRoot.SceneDraft.Date(childComplexity), true case "SceneDraft.details": if e.ComplexityRoot.SceneDraft.Details == nil { break } return e.ComplexityRoot.SceneDraft.Details(childComplexity), true case "SceneDraft.director": if e.ComplexityRoot.SceneDraft.Director == nil { break } return e.ComplexityRoot.SceneDraft.Director(childComplexity), true case "SceneDraft.fingerprints": if e.ComplexityRoot.SceneDraft.Fingerprints == nil { break } return e.ComplexityRoot.SceneDraft.Fingerprints(childComplexity), true case "SceneDraft.id": if e.ComplexityRoot.SceneDraft.ID == nil { break } return e.ComplexityRoot.SceneDraft.ID(childComplexity), true case "SceneDraft.image": if e.ComplexityRoot.SceneDraft.Image == nil { break } return e.ComplexityRoot.SceneDraft.Image(childComplexity), true case "SceneDraft.performers": if e.ComplexityRoot.SceneDraft.Performers == nil { break } return e.ComplexityRoot.SceneDraft.Performers(childComplexity), true case "SceneDraft.production_date": if e.ComplexityRoot.SceneDraft.ProductionDate == nil { break } return e.ComplexityRoot.SceneDraft.ProductionDate(childComplexity), true case "SceneDraft.studio": if e.ComplexityRoot.SceneDraft.Studio == nil { break } return e.ComplexityRoot.SceneDraft.Studio(childComplexity), true case "SceneDraft.tags": if e.ComplexityRoot.SceneDraft.Tags == nil { break } return e.ComplexityRoot.SceneDraft.Tags(childComplexity), true case "SceneDraft.title": if e.ComplexityRoot.SceneDraft.Title == nil { break } return e.ComplexityRoot.SceneDraft.Title(childComplexity), true case "SceneDraft.urls": if e.ComplexityRoot.SceneDraft.URLs == nil { break } return e.ComplexityRoot.SceneDraft.URLs(childComplexity), true case "SceneEdit.added_fingerprints": if e.ComplexityRoot.SceneEdit.AddedFingerprints == nil { break } return e.ComplexityRoot.SceneEdit.AddedFingerprints(childComplexity), true case "SceneEdit.added_images": if e.ComplexityRoot.SceneEdit.AddedImages == nil { break } return e.ComplexityRoot.SceneEdit.AddedImages(childComplexity), true case "SceneEdit.added_performers": if e.ComplexityRoot.SceneEdit.AddedPerformers == nil { break } return e.ComplexityRoot.SceneEdit.AddedPerformers(childComplexity), true case "SceneEdit.added_tags": if e.ComplexityRoot.SceneEdit.AddedTags == nil { break } return e.ComplexityRoot.SceneEdit.AddedTags(childComplexity), true case "SceneEdit.added_urls": if e.ComplexityRoot.SceneEdit.AddedUrls == nil { break } return e.ComplexityRoot.SceneEdit.AddedUrls(childComplexity), true case "SceneEdit.code": if e.ComplexityRoot.SceneEdit.Code == nil { break } return e.ComplexityRoot.SceneEdit.Code(childComplexity), true case "SceneEdit.date": if e.ComplexityRoot.SceneEdit.Date == nil { break } return e.ComplexityRoot.SceneEdit.Date(childComplexity), true case "SceneEdit.details": if e.ComplexityRoot.SceneEdit.Details == nil { break } return e.ComplexityRoot.SceneEdit.Details(childComplexity), true case "SceneEdit.director": if e.ComplexityRoot.SceneEdit.Director == nil { break } return e.ComplexityRoot.SceneEdit.Director(childComplexity), true case "SceneEdit.draft_id": if e.ComplexityRoot.SceneEdit.DraftID == nil { break } return e.ComplexityRoot.SceneEdit.DraftID(childComplexity), true case "SceneEdit.duration": if e.ComplexityRoot.SceneEdit.Duration == nil { break } return e.ComplexityRoot.SceneEdit.Duration(childComplexity), true case "SceneEdit.fingerprints": if e.ComplexityRoot.SceneEdit.Fingerprints == nil { break } return e.ComplexityRoot.SceneEdit.Fingerprints(childComplexity), true case "SceneEdit.images": if e.ComplexityRoot.SceneEdit.Images == nil { break } return e.ComplexityRoot.SceneEdit.Images(childComplexity), true case "SceneEdit.performers": if e.ComplexityRoot.SceneEdit.Performers == nil { break } return e.ComplexityRoot.SceneEdit.Performers(childComplexity), true case "SceneEdit.production_date": if e.ComplexityRoot.SceneEdit.ProductionDate == nil { break } return e.ComplexityRoot.SceneEdit.ProductionDate(childComplexity), true case "SceneEdit.removed_fingerprints": if e.ComplexityRoot.SceneEdit.RemovedFingerprints == nil { break } return e.ComplexityRoot.SceneEdit.RemovedFingerprints(childComplexity), true case "SceneEdit.removed_images": if e.ComplexityRoot.SceneEdit.RemovedImages == nil { break } return e.ComplexityRoot.SceneEdit.RemovedImages(childComplexity), true case "SceneEdit.removed_performers": if e.ComplexityRoot.SceneEdit.RemovedPerformers == nil { break } return e.ComplexityRoot.SceneEdit.RemovedPerformers(childComplexity), true case "SceneEdit.removed_tags": if e.ComplexityRoot.SceneEdit.RemovedTags == nil { break } return e.ComplexityRoot.SceneEdit.RemovedTags(childComplexity), true case "SceneEdit.removed_urls": if e.ComplexityRoot.SceneEdit.RemovedUrls == nil { break } return e.ComplexityRoot.SceneEdit.RemovedUrls(childComplexity), true case "SceneEdit.studio": if e.ComplexityRoot.SceneEdit.Studio == nil { break } return e.ComplexityRoot.SceneEdit.Studio(childComplexity), true case "SceneEdit.tags": if e.ComplexityRoot.SceneEdit.Tags == nil { break } return e.ComplexityRoot.SceneEdit.Tags(childComplexity), true case "SceneEdit.title": if e.ComplexityRoot.SceneEdit.Title == nil { break } return e.ComplexityRoot.SceneEdit.Title(childComplexity), true case "SceneEdit.urls": if e.ComplexityRoot.SceneEdit.Urls == nil { break } return e.ComplexityRoot.SceneEdit.Urls(childComplexity), true case "Site.created": if e.ComplexityRoot.Site.Created == nil { break } return e.ComplexityRoot.Site.Created(childComplexity), true case "Site.description": if e.ComplexityRoot.Site.Description == nil { break } return e.ComplexityRoot.Site.Description(childComplexity), true case "Site.id": if e.ComplexityRoot.Site.ID == nil { break } return e.ComplexityRoot.Site.ID(childComplexity), true case "Site.icon": if e.ComplexityRoot.Site.Icon == nil { break } return e.ComplexityRoot.Site.Icon(childComplexity), true case "Site.name": if e.ComplexityRoot.Site.Name == nil { break } return e.ComplexityRoot.Site.Name(childComplexity), true case "Site.regex": if e.ComplexityRoot.Site.Regex == nil { break } return e.ComplexityRoot.Site.Regex(childComplexity), true case "Site.url": if e.ComplexityRoot.Site.URL == nil { break } return e.ComplexityRoot.Site.URL(childComplexity), true case "Site.updated": if e.ComplexityRoot.Site.Updated == nil { break } return e.ComplexityRoot.Site.Updated(childComplexity), true case "Site.valid_types": if e.ComplexityRoot.Site.ValidTypes == nil { break } return e.ComplexityRoot.Site.ValidTypes(childComplexity), true case "StashBoxConfig.edit_update_limit": if e.ComplexityRoot.StashBoxConfig.EditUpdateLimit == nil { break } return e.ComplexityRoot.StashBoxConfig.EditUpdateLimit(childComplexity), true case "StashBoxConfig.guidelines_url": if e.ComplexityRoot.StashBoxConfig.GuidelinesURL == nil { break } return e.ComplexityRoot.StashBoxConfig.GuidelinesURL(childComplexity), true case "StashBoxConfig.host_url": if e.ComplexityRoot.StashBoxConfig.HostURL == nil { break } return e.ComplexityRoot.StashBoxConfig.HostURL(childComplexity), true case "StashBoxConfig.min_destructive_voting_period": if e.ComplexityRoot.StashBoxConfig.MinDestructiveVotingPeriod == nil { break } return e.ComplexityRoot.StashBoxConfig.MinDestructiveVotingPeriod(childComplexity), true case "StashBoxConfig.require_activation": if e.ComplexityRoot.StashBoxConfig.RequireActivation == nil { break } return e.ComplexityRoot.StashBoxConfig.RequireActivation(childComplexity), true case "StashBoxConfig.require_invite": if e.ComplexityRoot.StashBoxConfig.RequireInvite == nil { break } return e.ComplexityRoot.StashBoxConfig.RequireInvite(childComplexity), true case "StashBoxConfig.require_scene_draft": if e.ComplexityRoot.StashBoxConfig.RequireSceneDraft == nil { break } return e.ComplexityRoot.StashBoxConfig.RequireSceneDraft(childComplexity), true case "StashBoxConfig.require_tag_role": if e.ComplexityRoot.StashBoxConfig.RequireTagRole == nil { break } return e.ComplexityRoot.StashBoxConfig.RequireTagRole(childComplexity), true case "StashBoxConfig.vote_application_threshold": if e.ComplexityRoot.StashBoxConfig.VoteApplicationThreshold == nil { break } return e.ComplexityRoot.StashBoxConfig.VoteApplicationThreshold(childComplexity), true case "StashBoxConfig.vote_cron_interval": if e.ComplexityRoot.StashBoxConfig.VoteCronInterval == nil { break } return e.ComplexityRoot.StashBoxConfig.VoteCronInterval(childComplexity), true case "StashBoxConfig.vote_promotion_threshold": if e.ComplexityRoot.StashBoxConfig.VotePromotionThreshold == nil { break } return e.ComplexityRoot.StashBoxConfig.VotePromotionThreshold(childComplexity), true case "StashBoxConfig.voting_period": if e.ComplexityRoot.StashBoxConfig.VotingPeriod == nil { break } return e.ComplexityRoot.StashBoxConfig.VotingPeriod(childComplexity), true case "Studio.aliases": if e.ComplexityRoot.Studio.Aliases == nil { break } return e.ComplexityRoot.Studio.Aliases(childComplexity), true case "Studio.child_studios": if e.ComplexityRoot.Studio.ChildStudios == nil { break } return e.ComplexityRoot.Studio.ChildStudios(childComplexity), true case "Studio.created": if e.ComplexityRoot.Studio.Created == nil { break } return e.ComplexityRoot.Studio.Created(childComplexity), true case "Studio.deleted": if e.ComplexityRoot.Studio.Deleted == nil { break } return e.ComplexityRoot.Studio.Deleted(childComplexity), true case "Studio.id": if e.ComplexityRoot.Studio.ID == nil { break } return e.ComplexityRoot.Studio.ID(childComplexity), true case "Studio.images": if e.ComplexityRoot.Studio.Images == nil { break } return e.ComplexityRoot.Studio.Images(childComplexity), true case "Studio.is_favorite": if e.ComplexityRoot.Studio.IsFavorite == nil { break } return e.ComplexityRoot.Studio.IsFavorite(childComplexity), true case "Studio.name": if e.ComplexityRoot.Studio.Name == nil { break } return e.ComplexityRoot.Studio.Name(childComplexity), true case "Studio.parent": if e.ComplexityRoot.Studio.Parent == nil { break } return e.ComplexityRoot.Studio.Parent(childComplexity), true case "Studio.performers": if e.ComplexityRoot.Studio.Performers == nil { break } args, err := ec.field_Studio_performers_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Studio.Performers(childComplexity, args["input"].(PerformerQueryInput)), true case "Studio.sub_studios": if e.ComplexityRoot.Studio.SubStudios == nil { break } args, err := ec.field_Studio_sub_studios_args(ctx, rawArgs) if err != nil { return 0, false } return e.ComplexityRoot.Studio.SubStudios(childComplexity, args["input"].(*StudioQueryInput)), true case "Studio.updated": if e.ComplexityRoot.Studio.Updated == nil { break } return e.ComplexityRoot.Studio.Updated(childComplexity), true case "Studio.urls": if e.ComplexityRoot.Studio.Urls == nil { break } return e.ComplexityRoot.Studio.Urls(childComplexity), true case "StudioEdit.added_aliases": if e.ComplexityRoot.StudioEdit.AddedAliases == nil { break } return e.ComplexityRoot.StudioEdit.AddedAliases(childComplexity), true case "StudioEdit.added_images": if e.ComplexityRoot.StudioEdit.AddedImages == nil { break } return e.ComplexityRoot.StudioEdit.AddedImages(childComplexity), true case "StudioEdit.added_urls": if e.ComplexityRoot.StudioEdit.AddedUrls == nil { break } return e.ComplexityRoot.StudioEdit.AddedUrls(childComplexity), true case "StudioEdit.images": if e.ComplexityRoot.StudioEdit.Images == nil { break } return e.ComplexityRoot.StudioEdit.Images(childComplexity), true case "StudioEdit.name": if e.ComplexityRoot.StudioEdit.Name == nil { break } return e.ComplexityRoot.StudioEdit.Name(childComplexity), true case "StudioEdit.parent": if e.ComplexityRoot.StudioEdit.Parent == nil { break } return e.ComplexityRoot.StudioEdit.Parent(childComplexity), true case "StudioEdit.removed_aliases": if e.ComplexityRoot.StudioEdit.RemovedAliases == nil { break } return e.ComplexityRoot.StudioEdit.RemovedAliases(childComplexity), true case "StudioEdit.removed_images": if e.ComplexityRoot.StudioEdit.RemovedImages == nil { break } return e.ComplexityRoot.StudioEdit.RemovedImages(childComplexity), true case "StudioEdit.removed_urls": if e.ComplexityRoot.StudioEdit.RemovedUrls == nil { break } return e.ComplexityRoot.StudioEdit.RemovedUrls(childComplexity), true case "StudioEdit.urls": if e.ComplexityRoot.StudioEdit.Urls == nil { break } return e.ComplexityRoot.StudioEdit.Urls(childComplexity), true case "Tag.aliases": if e.ComplexityRoot.Tag.Aliases == nil { break } return e.ComplexityRoot.Tag.Aliases(childComplexity), true case "Tag.category": if e.ComplexityRoot.Tag.Category == nil { break } return e.ComplexityRoot.Tag.Category(childComplexity), true case "Tag.created": if e.ComplexityRoot.Tag.Created == nil { break } return e.ComplexityRoot.Tag.Created(childComplexity), true case "Tag.deleted": if e.ComplexityRoot.Tag.Deleted == nil { break } return e.ComplexityRoot.Tag.Deleted(childComplexity), true case "Tag.description": if e.ComplexityRoot.Tag.Description == nil { break } return e.ComplexityRoot.Tag.Description(childComplexity), true case "Tag.edits": if e.ComplexityRoot.Tag.Edits == nil { break } return e.ComplexityRoot.Tag.Edits(childComplexity), true case "Tag.id": if e.ComplexityRoot.Tag.ID == nil { break } return e.ComplexityRoot.Tag.ID(childComplexity), true case "Tag.name": if e.ComplexityRoot.Tag.Name == nil { break } return e.ComplexityRoot.Tag.Name(childComplexity), true case "Tag.updated": if e.ComplexityRoot.Tag.Updated == nil { break } return e.ComplexityRoot.Tag.Updated(childComplexity), true case "TagCategory.description": if e.ComplexityRoot.TagCategory.Description == nil { break } return e.ComplexityRoot.TagCategory.Description(childComplexity), true case "TagCategory.group": if e.ComplexityRoot.TagCategory.Group == nil { break } return e.ComplexityRoot.TagCategory.Group(childComplexity), true case "TagCategory.id": if e.ComplexityRoot.TagCategory.ID == nil { break } return e.ComplexityRoot.TagCategory.ID(childComplexity), true case "TagCategory.name": if e.ComplexityRoot.TagCategory.Name == nil { break } return e.ComplexityRoot.TagCategory.Name(childComplexity), true case "TagEdit.added_aliases": if e.ComplexityRoot.TagEdit.AddedAliases == nil { break } return e.ComplexityRoot.TagEdit.AddedAliases(childComplexity), true case "TagEdit.aliases": if e.ComplexityRoot.TagEdit.Aliases == nil { break } return e.ComplexityRoot.TagEdit.Aliases(childComplexity), true case "TagEdit.category": if e.ComplexityRoot.TagEdit.Category == nil { break } return e.ComplexityRoot.TagEdit.Category(childComplexity), true case "TagEdit.description": if e.ComplexityRoot.TagEdit.Description == nil { break } return e.ComplexityRoot.TagEdit.Description(childComplexity), true case "TagEdit.name": if e.ComplexityRoot.TagEdit.Name == nil { break } return e.ComplexityRoot.TagEdit.Name(childComplexity), true case "TagEdit.removed_aliases": if e.ComplexityRoot.TagEdit.RemovedAliases == nil { break } return e.ComplexityRoot.TagEdit.RemovedAliases(childComplexity), true case "URL.site": if e.ComplexityRoot.URL.Site == nil { break } return e.ComplexityRoot.URL.Site(childComplexity), true case "URL.type": if e.ComplexityRoot.URL.Type == nil { break } return e.ComplexityRoot.URL.Type(childComplexity), true case "URL.url": if e.ComplexityRoot.URL.URL == nil { break } return e.ComplexityRoot.URL.URL(childComplexity), true case "UpdatedEdit.edit": if e.ComplexityRoot.UpdatedEdit.Edit == nil { break } return e.ComplexityRoot.UpdatedEdit.Edit(childComplexity), true case "User.api_calls": if e.ComplexityRoot.User.APICalls == nil { break } return e.ComplexityRoot.User.APICalls(childComplexity), true case "User.api_key": if e.ComplexityRoot.User.APIKey == nil { break } return e.ComplexityRoot.User.APIKey(childComplexity), true case "User.active_invite_codes": if e.ComplexityRoot.User.ActiveInviteCodes == nil { break } return e.ComplexityRoot.User.ActiveInviteCodes(childComplexity), true case "User.edit_count": if e.ComplexityRoot.User.EditCount == nil { break } return e.ComplexityRoot.User.EditCount(childComplexity), true case "User.email": if e.ComplexityRoot.User.Email == nil { break } return e.ComplexityRoot.User.Email(childComplexity), true case "User.id": if e.ComplexityRoot.User.ID == nil { break } return e.ComplexityRoot.User.ID(childComplexity), true case "User.invite_codes": if e.ComplexityRoot.User.InviteCodes == nil { break } return e.ComplexityRoot.User.InviteCodes(childComplexity), true case "User.invite_tokens": if e.ComplexityRoot.User.InviteTokens == nil { break } return e.ComplexityRoot.User.InviteTokens(childComplexity), true case "User.invited_by": if e.ComplexityRoot.User.InvitedBy == nil { break } return e.ComplexityRoot.User.InvitedBy(childComplexity), true case "User.name": if e.ComplexityRoot.User.Name == nil { break } return e.ComplexityRoot.User.Name(childComplexity), true case "User.notification_subscriptions": if e.ComplexityRoot.User.NotificationSubscriptions == nil { break } return e.ComplexityRoot.User.NotificationSubscriptions(childComplexity), true case "User.roles": if e.ComplexityRoot.User.Roles == nil { break } return e.ComplexityRoot.User.Roles(childComplexity), true case "User.vote_count": if e.ComplexityRoot.User.VoteCount == nil { break } return e.ComplexityRoot.User.VoteCount(childComplexity), true case "UserEditCount.accepted": if e.ComplexityRoot.UserEditCount.Accepted == nil { break } return e.ComplexityRoot.UserEditCount.Accepted(childComplexity), true case "UserEditCount.canceled": if e.ComplexityRoot.UserEditCount.Canceled == nil { break } return e.ComplexityRoot.UserEditCount.Canceled(childComplexity), true case "UserEditCount.failed": if e.ComplexityRoot.UserEditCount.Failed == nil { break } return e.ComplexityRoot.UserEditCount.Failed(childComplexity), true case "UserEditCount.immediate_accepted": if e.ComplexityRoot.UserEditCount.ImmediateAccepted == nil { break } return e.ComplexityRoot.UserEditCount.ImmediateAccepted(childComplexity), true case "UserEditCount.immediate_rejected": if e.ComplexityRoot.UserEditCount.ImmediateRejected == nil { break } return e.ComplexityRoot.UserEditCount.ImmediateRejected(childComplexity), true case "UserEditCount.pending": if e.ComplexityRoot.UserEditCount.Pending == nil { break } return e.ComplexityRoot.UserEditCount.Pending(childComplexity), true case "UserEditCount.rejected": if e.ComplexityRoot.UserEditCount.Rejected == nil { break } return e.ComplexityRoot.UserEditCount.Rejected(childComplexity), true case "UserVoteCount.abstain": if e.ComplexityRoot.UserVoteCount.Abstain == nil { break } return e.ComplexityRoot.UserVoteCount.Abstain(childComplexity), true case "UserVoteCount.accept": if e.ComplexityRoot.UserVoteCount.Accept == nil { break } return e.ComplexityRoot.UserVoteCount.Accept(childComplexity), true case "UserVoteCount.immediate_accept": if e.ComplexityRoot.UserVoteCount.ImmediateAccept == nil { break } return e.ComplexityRoot.UserVoteCount.ImmediateAccept(childComplexity), true case "UserVoteCount.immediate_reject": if e.ComplexityRoot.UserVoteCount.ImmediateReject == nil { break } return e.ComplexityRoot.UserVoteCount.ImmediateReject(childComplexity), true case "UserVoteCount.reject": if e.ComplexityRoot.UserVoteCount.Reject == nil { break } return e.ComplexityRoot.UserVoteCount.Reject(childComplexity), true case "Version.build_time": if e.ComplexityRoot.Version.BuildTime == nil { break } return e.ComplexityRoot.Version.BuildTime(childComplexity), true case "Version.build_type": if e.ComplexityRoot.Version.BuildType == nil { break } return e.ComplexityRoot.Version.BuildType(childComplexity), true case "Version.hash": if e.ComplexityRoot.Version.Hash == nil { break } return e.ComplexityRoot.Version.Hash(childComplexity), true case "Version.version": if e.ComplexityRoot.Version.Version == nil { break } return e.ComplexityRoot.Version.Version(childComplexity), true } return 0, false } func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { opCtx := graphql.GetOperationContext(ctx) ec := newExecutionContext(opCtx, e, make(chan graphql.DeferredResult)) inputUnmarshalMap := graphql.BuildUnmarshalerMap( ec.unmarshalInputActivateNewUserInput, ec.unmarshalInputAmendEditInput, ec.unmarshalInputAmendItemRemoval, ec.unmarshalInputApplyEditInput, ec.unmarshalInputBodyModificationCriterionInput, ec.unmarshalInputBodyModificationInput, ec.unmarshalInputBreastTypeCriterionInput, ec.unmarshalInputCancelEditInput, ec.unmarshalInputDateCriterionInput, ec.unmarshalInputDeleteEditInput, ec.unmarshalInputDeleteFingerprintSubmissionsInput, ec.unmarshalInputDraftEntityInput, ec.unmarshalInputEditCommentInput, ec.unmarshalInputEditInput, ec.unmarshalInputEditQueryInput, ec.unmarshalInputEditVoteInput, ec.unmarshalInputEyeColorCriterionInput, ec.unmarshalInputFingerprintBatchSubmission, ec.unmarshalInputFingerprintEditInput, ec.unmarshalInputFingerprintInput, ec.unmarshalInputFingerprintQueryInput, ec.unmarshalInputFingerprintSubmission, ec.unmarshalInputGenerateInviteCodeInput, ec.unmarshalInputGrantInviteInput, ec.unmarshalInputHairColorCriterionInput, ec.unmarshalInputIDCriterionInput, ec.unmarshalInputImageCreateInput, ec.unmarshalInputImageDestroyInput, ec.unmarshalInputImageUpdateInput, ec.unmarshalInputIntCriterionInput, ec.unmarshalInputMarkNotificationReadInput, ec.unmarshalInputModAuditQueryInput, ec.unmarshalInputMoveFingerprintSubmissionsInput, ec.unmarshalInputMultiIDCriterionInput, ec.unmarshalInputMultiStringCriterionInput, ec.unmarshalInputNewUserInput, ec.unmarshalInputPerformerAppearanceInput, ec.unmarshalInputPerformerCreateInput, ec.unmarshalInputPerformerDestroyInput, ec.unmarshalInputPerformerDraftInput, ec.unmarshalInputPerformerEditDetailsInput, ec.unmarshalInputPerformerEditInput, ec.unmarshalInputPerformerEditOptionsInput, ec.unmarshalInputPerformerQueryInput, ec.unmarshalInputPerformerScenesInput, ec.unmarshalInputPerformerSearchFilter, ec.unmarshalInputPerformerUpdateInput, ec.unmarshalInputQueryExistingPerformerInput, ec.unmarshalInputQueryExistingSceneInput, ec.unmarshalInputQueryNotificationsInput, ec.unmarshalInputResetPasswordInput, ec.unmarshalInputRevokeInviteInput, ec.unmarshalInputRoleCriterionInput, ec.unmarshalInputSceneCreateInput, ec.unmarshalInputSceneDestroyInput, ec.unmarshalInputSceneDraftInput, ec.unmarshalInputSceneEditDetailsInput, ec.unmarshalInputSceneEditInput, ec.unmarshalInputSceneQueryInput, ec.unmarshalInputSceneUpdateInput, ec.unmarshalInputSiteCreateInput, ec.unmarshalInputSiteDestroyInput, ec.unmarshalInputSiteUpdateInput, ec.unmarshalInputStringCriterionInput, ec.unmarshalInputStudioCreateInput, ec.unmarshalInputStudioDestroyInput, ec.unmarshalInputStudioEditDetailsInput, ec.unmarshalInputStudioEditInput, ec.unmarshalInputStudioQueryInput, ec.unmarshalInputStudioUpdateInput, ec.unmarshalInputTagCategoryCreateInput, ec.unmarshalInputTagCategoryDestroyInput, ec.unmarshalInputTagCategoryUpdateInput, ec.unmarshalInputTagCreateInput, ec.unmarshalInputTagDestroyInput, ec.unmarshalInputTagEditDetailsInput, ec.unmarshalInputTagEditInput, ec.unmarshalInputTagQueryInput, ec.unmarshalInputTagUpdateInput, ec.unmarshalInputURLInput, ec.unmarshalInputUserChangeEmailInput, ec.unmarshalInputUserChangePasswordInput, ec.unmarshalInputUserCreateInput, ec.unmarshalInputUserDestroyInput, ec.unmarshalInputUserQueryInput, ec.unmarshalInputUserUpdateInput, ) first := true switch opCtx.Operation.Operation { case ast.Query: return func(ctx context.Context) *graphql.Response { var response graphql.Response var data graphql.Marshaler if first { first = false ctx = graphql.WithUnmarshalerMap(ctx, inputUnmarshalMap) data = ec._Query(ctx, opCtx.Operation.SelectionSet) } else { if atomic.LoadInt32(&ec.PendingDeferred) > 0 { result := <-ec.DeferredResults atomic.AddInt32(&ec.PendingDeferred, -1) data = result.Result response.Path = result.Path response.Label = result.Label response.Errors = result.Errors } else { return nil } } var buf bytes.Buffer data.MarshalGQL(&buf) response.Data = buf.Bytes() if atomic.LoadInt32(&ec.Deferred) > 0 { hasNext := atomic.LoadInt32(&ec.PendingDeferred) > 0 response.HasNext = &hasNext } return &response } case ast.Mutation: return func(ctx context.Context) *graphql.Response { if !first { return nil } first = false ctx = graphql.WithUnmarshalerMap(ctx, inputUnmarshalMap) data := ec._Mutation(ctx, opCtx.Operation.SelectionSet) var buf bytes.Buffer data.MarshalGQL(&buf) return &graphql.Response{ Data: buf.Bytes(), } } default: return graphql.OneShot(graphql.ErrorResponse(ctx, "unsupported GraphQL operation")) } } type executionContext struct { *graphql.ExecutionContextState[ResolverRoot, DirectiveRoot, ComplexityRoot] } func newExecutionContext( opCtx *graphql.OperationContext, execSchema *executableSchema, deferredResults chan graphql.DeferredResult, ) executionContext { return executionContext{ ExecutionContextState: graphql.NewExecutionContextState[ResolverRoot, DirectiveRoot, ComplexityRoot]( opCtx, (*graphql.ExecutableSchemaState[ResolverRoot, DirectiveRoot, ComplexityRoot])(execSchema), parsedSchema, deferredResults, ), } } var sources = []*ast.Source{ {Name: "../../graphql/schema/types/config.graphql", Input: `type StashBoxConfig { host_url: String! require_invite: Boolean! require_activation: Boolean! vote_promotion_threshold: Int vote_application_threshold: Int! voting_period: Int! min_destructive_voting_period: Int! vote_cron_interval: String! guidelines_url: String! require_scene_draft: Boolean! edit_update_limit: Int! require_tag_role: Boolean! } `, BuiltIn: false}, {Name: "../../graphql/schema/types/draft.graphql", Input: `type DraftSubmissionStatus { id: ID } type DraftEntity { name: String! id: ID } input DraftEntityInput { name: String! id: ID } type Draft { id: ID! created: Time! expires: Time! data: DraftData! } union DraftData = SceneDraft | PerformerDraft `, BuiltIn: false}, {Name: "../../graphql/schema/types/edit.graphql", Input: `enum OperationEnum { CREATE MODIFY DESTROY MERGE } enum VoteTypeEnum { ABSTAIN ACCEPT REJECT """Immediately accepts the edit - bypassing the vote""" IMMEDIATE_ACCEPT """Immediately rejects the edit - bypassing the vote""" IMMEDIATE_REJECT } enum VoteStatusEnum { ACCEPTED REJECTED PENDING IMMEDIATE_ACCEPTED IMMEDIATE_REJECTED FAILED CANCELED } type EditVote { user: User date: Time! vote: VoteTypeEnum! } type EditComment { id: ID! user: User date: Time! comment: String! edit: Edit! } union EditDetails = PerformerEdit | SceneEdit | StudioEdit | TagEdit enum TargetTypeEnum { SCENE STUDIO PERFORMER TAG } union EditTarget = Performer | Scene | Studio | Tag type Edit { id: ID! user: User """Object being edited - null if creating a new object""" target: EditTarget target_type: TargetTypeEnum! """Objects to merge with the target. Only applicable to merges""" merge_sources: [EditTarget!]! operation: OperationEnum! bot: Boolean! details: EditDetails """Previous state of fields being modified - null if operation is create or delete.""" old_details: EditDetails """Entity specific options""" options: PerformerEditOptions comments: [EditComment!]! votes: [EditVote!]! """ = Accepted - Rejected""" vote_count: Int! """Is the edit considered destructive.""" destructive: Boolean! status: VoteStatusEnum! applied: Boolean! update_count: Int! updatable: Boolean! created: Time! updated: Time closed: Time expires: Time } input EditInput { """Not required for create type""" id: ID operation: OperationEnum! """Only required for merge type""" merge_source_ids: [ID!] comment: String """Edit submitted by an automated script. Requires bot permission""" bot: Boolean } input EditVoteInput { id: ID! vote: VoteTypeEnum! } input EditCommentInput { id: ID! comment: String! } type QueryEditsResultType { count: Int! edits: [Edit!]! } enum EditSortEnum { CREATED_AT UPDATED_AT CLOSED_AT } enum UserVotedFilterEnum { ABSTAIN ACCEPT REJECT NOT_VOTED } input EditQueryInput { """Filter by user id""" user_id: ID """Filter by status""" status: VoteStatusEnum """Filter by operation""" operation: OperationEnum """Filter by vote count""" vote_count: IntCriterionInput """Filter by applied status""" applied: Boolean """Filter by target type""" target_type: TargetTypeEnum """Filter by target id""" target_id: ID """Filter by favorite status""" is_favorite: Boolean """Filter by user voted status""" voted: UserVotedFilterEnum """Filter to bot edits only""" is_bot: Boolean """Filter out user's own edits""" include_user_submitted: Boolean page: Int! = 1 per_page: Int! = 25 direction: SortDirectionEnum! = DESC sort: EditSortEnum! = CREATED_AT } input ApplyEditInput { id: ID! } input CancelEditInput { id: ID! } input DeleteEditInput { id: ID! reason: String! } input AmendEditInput { id: ID! reason: String! """Fields to remove from the diff (e.g., ["name", "disambiguation"])""" remove_fields: [String!] """Array items to remove from added arrays""" remove_added_items: [AmendItemRemoval!] """Array items to remove from removed arrays""" remove_removed_items: [AmendItemRemoval!] } input AmendItemRemoval { """Field name (e.g., "aliases", "urls", "images")""" field: String! """Indices to remove from the array""" indices: [Int!]! } `, BuiltIn: false}, {Name: "../../graphql/schema/types/filter.graphql", Input: `input MultiIDCriterionInput { value: [ID!] modifier: CriterionModifier! } input IDCriterionInput { value: [ID!]! modifier: CriterionModifier! } input StringCriterionInput { value: String! modifier: CriterionModifier! } input MultiStringCriterionInput { value: [String!]! modifier: CriterionModifier! } input IntCriterionInput { value: Int! modifier: CriterionModifier! } input DateCriterionInput { value: Date! modifier: CriterionModifier! } enum CriterionModifier { """=""" EQUALS, """!=""" NOT_EQUALS, """>""" GREATER_THAN, """<""" LESS_THAN, """IS NULL""" IS_NULL, """IS NOT NULL""" NOT_NULL, """INCLUDES ALL""" INCLUDES_ALL, INCLUDES, EXCLUDES, }`, BuiltIn: false}, {Name: "../../graphql/schema/types/image.graphql", Input: `scalar Upload type Image { id: ID! url: String! width: Int! height: Int! } input ImageCreateInput { url: String file: Upload } input ImageUpdateInput { id: ID! url: String } input ImageDestroyInput { id: ID! } `, BuiltIn: false}, {Name: "../../graphql/schema/types/misc.graphql", Input: `scalar Date scalar DateTime scalar Time scalar FingerprintHash enum DateAccuracyEnum { YEAR MONTH DAY } type FuzzyDate { date: Date! accuracy: DateAccuracyEnum! } enum SortDirectionEnum { ASC DESC } type URL { url: String! type: String! @deprecated(reason: "Use the site field instead") site: Site! } input URLInput { url: String! site_id: ID! } `, BuiltIn: false}, {Name: "../../graphql/schema/types/mod_audit.graphql", Input: `enum ModAuditActionEnum { EDIT_DELETE EDIT_AMENDMENT } type ModAudit { id: ID! action: ModAuditActionEnum! user: User target_id: ID! target_type: String! data: String! reason: String created_at: Time! } type QueryModAuditsResultType { count: Int! audits: [ModAudit!]! } input ModAuditQueryInput { page: Int! = 1 per_page: Int! = 25 action: ModAuditActionEnum user_id: ID } `, BuiltIn: false}, {Name: "../../graphql/schema/types/notifications.graphql", Input: `type Notification { created: Time! read: Boolean! data: NotificationData! } enum NotificationEnum { FAVORITE_PERFORMER_SCENE FAVORITE_PERFORMER_EDIT FAVORITE_STUDIO_SCENE FAVORITE_STUDIO_EDIT COMMENT_OWN_EDIT DOWNVOTE_OWN_EDIT FAILED_OWN_EDIT COMMENT_COMMENTED_EDIT COMMENT_VOTED_EDIT UPDATED_EDIT FINGERPRINTED_SCENE_EDIT } union NotificationData = | FavoritePerformerScene | FavoritePerformerEdit | FavoriteStudioScene | FavoriteStudioEdit | CommentOwnEdit | CommentCommentedEdit | CommentVotedEdit | DownvoteOwnEdit | FailedOwnEdit | UpdatedEdit | FingerprintedSceneEdit type FavoritePerformerScene { scene: Scene! } type FavoritePerformerEdit { edit: Edit! } type FavoriteStudioScene { scene: Scene! } type FavoriteStudioEdit { edit: Edit! } type CommentOwnEdit { comment: EditComment! } type DownvoteOwnEdit { edit: Edit! } type FailedOwnEdit { edit: Edit! } type CommentCommentedEdit { comment: EditComment! } type CommentVotedEdit { comment: EditComment! } type UpdatedEdit { edit: Edit! } type FingerprintedSceneEdit { edit: Edit! } input QueryNotificationsInput { page: Int! = 1 per_page: Int! = 25 type: NotificationEnum unread_only: Boolean } type QueryNotificationsResult { count: Int! notifications: [Notification!]! } input MarkNotificationReadInput { type: NotificationEnum! id: ID! } `, BuiltIn: false}, {Name: "../../graphql/schema/types/performer.graphql", Input: `enum GenderEnum { MALE FEMALE TRANSGENDER_MALE TRANSGENDER_FEMALE INTERSEX NON_BINARY } enum GenderFilterEnum { UNKNOWN MALE FEMALE TRANSGENDER_MALE TRANSGENDER_FEMALE INTERSEX NON_BINARY } enum BreastTypeEnum { NATURAL FAKE NA } type Measurements { cup_size: String band_size: Int waist: Int hip: Int } enum EthnicityEnum { CAUCASIAN BLACK ASIAN INDIAN LATIN MIDDLE_EASTERN MIXED OTHER } enum EthnicityFilterEnum { UNKNOWN CAUCASIAN BLACK ASIAN INDIAN LATIN MIDDLE_EASTERN MIXED OTHER } enum EyeColorEnum { BLUE BROWN GREY GREEN HAZEL RED } enum HairColorEnum { BLONDE BRUNETTE BLACK RED AUBURN GREY BALD VARIOUS WHITE OTHER } type BodyModification { location: String! description: String } input BodyModificationInput { location: String! description: String } type Performer { id: ID! name: String! disambiguation: String aliases: [String!]! gender: GenderEnum urls: [URL!]! birthdate: FuzzyDate @deprecated(reason: "Please use ` + "`" + `birth_date` + "`" + `") birth_date: String death_date: String age: Int # resolver ethnicity: EthnicityEnum country: String eye_color: EyeColorEnum hair_color: HairColorEnum """Height in cm""" height: Int measurements: Measurements! @deprecated(reason: "Use individual fields, cup/band/waist/hip_size") cup_size: String band_size: Int waist_size: Int hip_size: Int breast_type: BreastTypeEnum career_start_year: Int career_end_year: Int tattoos: [BodyModification!] piercings: [BodyModification!] images: [Image!]! deleted: Boolean! edits: [Edit!]! scene_count: Int! scenes(input: PerformerScenesInput): [Scene!]! """IDs of performers that were merged into this one""" merged_ids: [ID!]! """ID of performer that replaces this one""" merged_into_id: ID studios(studio_id: ID): [PerformerStudio!]! is_favorite: Boolean! created: Time! updated: Time! } input PerformerScenesInput { """Filter by another performer that also performs in the scenes""" performed_with: ID """Filter by a studio""" studio_id: ID """Filter by tags""" tags: MultiIDCriterionInput } type PerformerStudio { studio: Studio! scene_count: Int! } input PerformerCreateInput { name: String! disambiguation: String aliases: [String!] gender: GenderEnum urls: [URLInput!] birthdate: String deathdate: String ethnicity: EthnicityEnum country: String eye_color: EyeColorEnum hair_color: HairColorEnum height: Int cup_size: String band_size: Int waist_size: Int hip_size: Int breast_type: BreastTypeEnum career_start_year: Int career_end_year: Int tattoos: [BodyModificationInput!] piercings: [BodyModificationInput!] image_ids: [ID!] draft_id: ID } input PerformerUpdateInput { id: ID! name: String disambiguation: String aliases: [String!] gender: GenderEnum urls: [URLInput!] birthdate: String deathdate: String ethnicity: EthnicityEnum country: String eye_color: EyeColorEnum hair_color: HairColorEnum height: Int cup_size: String band_size: Int waist_size: Int hip_size: Int breast_type: BreastTypeEnum career_start_year: Int career_end_year: Int tattoos: [BodyModificationInput!] piercings: [BodyModificationInput!] image_ids: [ID!] } input PerformerDestroyInput { id: ID! } input PerformerEditDetailsInput { name: String disambiguation: String aliases: [String!] gender: GenderEnum urls: [URLInput!] birthdate: String deathdate: String ethnicity: EthnicityEnum country: String eye_color: EyeColorEnum hair_color: HairColorEnum height: Int cup_size: String band_size: Int waist_size: Int hip_size: Int breast_type: BreastTypeEnum career_start_year: Int career_end_year: Int tattoos: [BodyModificationInput!] piercings: [BodyModificationInput!] image_ids: [ID!] draft_id: ID } input PerformerEditOptionsInput { """Set performer alias on scenes without alias to old name if name is changed""" set_modify_aliases: Boolean = false """Set performer alias on scenes attached to merge sources to old name""" set_merge_aliases: Boolean = true } input PerformerEditInput { edit: EditInput! """Not required for destroy type""" details: PerformerEditDetailsInput """Controls aliases modification for merges and name modifications""" options: PerformerEditOptionsInput } type PerformerEdit { name: String disambiguation: String added_aliases: [String!] removed_aliases: [String!] gender: GenderEnum added_urls: [URL!] removed_urls: [URL!] birthdate: String deathdate: String ethnicity: EthnicityEnum country: String eye_color: EyeColorEnum hair_color: HairColorEnum """Height in cm""" height: Int cup_size: String band_size: Int waist_size: Int hip_size: Int breast_type: BreastTypeEnum career_start_year: Int career_end_year: Int added_tattoos: [BodyModification!] removed_tattoos: [BodyModification!] added_piercings: [BodyModification!] removed_piercings: [BodyModification!] added_images: [Image!] removed_images: [Image!] draft_id: ID aliases: [String!]! urls: [URL!]! images: [Image!]! tattoos: [BodyModification!]! piercings: [BodyModification!]! } type PerformerEditOptions { """Set performer alias on scenes without alias to old name if name is changed""" set_modify_aliases: Boolean! """Set performer alias on scenes attached to merge sources to old name""" set_merge_aliases: Boolean! } type GenderFacet { gender: GenderEnum! count: Int! } type PerformerSearchFacets { genders: [GenderFacet!]! } type QueryPerformersResultType { count: Int! performers: [Performer!]! """Search facets, only available for searchPerformer queries""" facets: PerformerSearchFacets } input BreastTypeCriterionInput { value: BreastTypeEnum modifier: CriterionModifier! } input EyeColorCriterionInput { value: EyeColorEnum modifier: CriterionModifier! } input HairColorCriterionInput { value: HairColorEnum modifier: CriterionModifier! } input BodyModificationCriterionInput { location: String description: String modifier: CriterionModifier! } enum PerformerSortEnum { NAME BIRTHDATE DEATHDATE SCENE_COUNT CAREER_START_YEAR DEBUT LAST_SCENE CREATED_AT UPDATED_AT } input PerformerSearchFilter { """Filter by gender""" gender: GenderEnum } input PerformerQueryInput { """Searches name and disambiguation - assumes like query unless quoted""" names: String """Searches name only - assumes like query unless quoted""" name: String """Search aliases only - assumes like query unless quoted""" alias: String disambiguation: StringCriterionInput gender: GenderFilterEnum """Filter to search urls - assumes like query unless quoted""" url: String birthdate: DateCriterionInput deathdate: DateCriterionInput birth_year: IntCriterionInput age: IntCriterionInput ethnicity: EthnicityFilterEnum country: StringCriterionInput eye_color: EyeColorCriterionInput hair_color: HairColorCriterionInput height: IntCriterionInput cup_size: StringCriterionInput band_size: IntCriterionInput waist_size: IntCriterionInput hip_size: IntCriterionInput breast_type: BreastTypeCriterionInput career_start_year: IntCriterionInput career_end_year: IntCriterionInput tattoos: BodyModificationCriterionInput piercings: BodyModificationCriterionInput """Filter by performerfavorite status for the current user""" is_favorite: Boolean """Filter by a performer they have performed in scenes with""" performed_with: ID """Filter by a studio""" studio_id: ID page: Int! = 1 per_page: Int! = 25 direction: SortDirectionEnum! = DESC sort: PerformerSortEnum! = CREATED_AT } type PerformerDraft { id: ID name: String! disambiguation: String aliases: String gender: String birthdate: String deathdate: String urls: [String!] ethnicity: String country: String eye_color: String hair_color: String height: String measurements: String breast_type: String tattoos: String piercings: String career_start_year: Int career_end_year: Int image: Image } input PerformerDraftInput { id: ID disambiguation: String name: String! aliases: String gender: String birthdate: String deathdate: String urls: [String!] ethnicity: String country: String eye_color: String hair_color: String height: String measurements: String breast_type: String tattoos: String piercings: String career_start_year: Int career_end_year: Int image: Upload } input QueryExistingPerformerInput { name: String disambiguation: String urls: [String!]! } type QueryExistingPerformerResult { edits: [Edit!]! performers: [Performer!]! } `, BuiltIn: false}, {Name: "../../graphql/schema/types/scene.graphql", Input: `type PerformerAppearance { performer: Performer! """Performing as alias""" as: String } input PerformerAppearanceInput { performer_id: ID! """Performing as alias""" as: String } enum FingerprintAlgorithm { MD5 OSHASH PHASH } enum FavoriteFilter { PERFORMER STUDIO ALL } enum FingerprintSubmissionType { "Positive vote" VALID "Report as invalid" INVALID "Remove vote" REMOVE } type Fingerprint { hash: FingerprintHash! algorithm: FingerprintAlgorithm! duration: Int! "number of times this fingerprint has been submitted (excluding reports)" submissions: Int! "number of times this fingerprint has been reported" reports: Int! created: Time! updated: Time! "true if the current user submitted this fingerprint" user_submitted: Boolean! "true if the current user reported this fingerprint" user_reported: Boolean! } type DraftFingerprint { hash: FingerprintHash! algorithm: FingerprintAlgorithm! duration: Int! } input FingerprintInput { """assumes current user if omitted. Ignored for non-modify Users""" user_ids: [ID!] hash: FingerprintHash! algorithm: FingerprintAlgorithm! duration: Int! } input FingerprintEditInput { user_ids: [ID!] hash: FingerprintHash! algorithm: FingerprintAlgorithm! duration: Int! created: Time! submissions: Int @deprecated(reason: "Unused") updated: Time @deprecated(reason: "Unused") } input FingerprintQueryInput { hash: FingerprintHash! algorithm: FingerprintAlgorithm! } input FingerprintSubmission { scene_id: ID! fingerprint: FingerprintInput! unmatch: Boolean @deprecated(reason: "Use ` + "`" + `vote` + "`" + ` with REMOVE instead") vote: FingerprintSubmissionType = VALID } input FingerprintBatchSubmission { scene_id: ID! hash: FingerprintHash! algorithm: FingerprintAlgorithm! duration: Int! } type FingerprintSubmissionResult { """The fingerprint hash that was submitted""" hash: FingerprintHash! """The scene ID that was submitted to""" scene_id: ID! """Error message if submission failed""" error: String } input MoveFingerprintSubmissionsInput { fingerprints: [FingerprintQueryInput!]! source_scene_id: ID! target_scene_id: ID! } input DeleteFingerprintSubmissionsInput { fingerprints: [FingerprintQueryInput!]! scene_id: ID! } type Scene { id: ID! title: String details: String date: String @deprecated(reason: "Please use ` + "`" + `release_date` + "`" + ` instead") release_date: String production_date: String urls: [URL!]! studio: Studio tags: [Tag!]! images: [Image!]! performers: [PerformerAppearance!]! fingerprints(is_submitted: Boolean = False): [Fingerprint!]! duration: Int director: String code: String deleted: Boolean! edits: [Edit!]! created: Time! updated: Time! } input SceneCreateInput { title: String details: String urls: [URLInput!] date: String! production_date: String studio_id: ID performers: [PerformerAppearanceInput!] tag_ids: [ID!] image_ids: [ID!] fingerprints: [FingerprintEditInput!]! duration: Int director: String code: String } input SceneUpdateInput { id: ID! title: String details: String urls: [URLInput!] date: String production_date: String studio_id: ID performers: [PerformerAppearanceInput!] tag_ids: [ID!] image_ids: [ID!] fingerprints: [FingerprintEditInput!] duration: Int director: String code: String } input SceneDestroyInput { id: ID! } input SceneEditDetailsInput { title: String details: String urls: [URLInput!] date: String production_date: String studio_id: ID performers: [PerformerAppearanceInput!] tag_ids: [ID!] image_ids: [ID!] duration: Int director: String code: String fingerprints: [FingerprintInput!] draft_id: ID } input SceneEditInput { edit: EditInput! """Not required for destroy type""" details: SceneEditDetailsInput } type SceneEdit { title: String details: String added_urls: [URL!] removed_urls: [URL!] date: String production_date: String studio: Studio """Added or modified performer appearance entries""" added_performers: [PerformerAppearance!] removed_performers: [PerformerAppearance!] added_tags: [Tag!] removed_tags: [Tag!] added_images: [Image!] removed_images: [Image!] added_fingerprints: [Fingerprint!] removed_fingerprints: [Fingerprint!] duration: Int director: String code: String draft_id: ID urls: [URL!]! performers: [PerformerAppearance!]! tags: [Tag!]! images: [Image!]! fingerprints: [Fingerprint!]! } type QueryScenesResultType { count: Int! scenes: [Scene!]! } enum SceneSortEnum { TITLE DATE TRENDING CREATED_AT UPDATED_AT } input SceneQueryInput { """Filter to search title and details - assumes like query unless quoted""" text: String """Filter to search title - assumes like query unless quoted""" title: String """Filter to search urls - assumes like query unless quoted""" url: String """Filter by date""" date: DateCriterionInput """Filter by production date""" production_date: DateCriterionInput """Filter to only include scenes with this studio""" studios: MultiIDCriterionInput """Filter to only include scenes with this studio as primary or parent""" parentStudio: String """Filter to only include scenes with these tags""" tags: MultiIDCriterionInput """Filter to only include scenes with these performers""" performers: MultiIDCriterionInput """Filter to include scenes with performer appearing as alias""" alias: StringCriterionInput """Filter to only include scenes with these fingerprints""" fingerprints: MultiStringCriterionInput """Filter by favorited entity""" favorites: FavoriteFilter """Filter to scenes with fingerprints submitted by the user""" has_fingerprint_submissions: Boolean = False page: Int! = 1 per_page: Int! = 25 direction: SortDirectionEnum! = DESC sort: SceneSortEnum! = DATE } union SceneDraftStudio = Studio | DraftEntity union SceneDraftPerformer = Performer | DraftEntity union SceneDraftTag = Tag | DraftEntity type SceneDraft { id: ID title: String code: String details: String director: String urls: [String!] date: String production_date: String studio: SceneDraftStudio performers: [SceneDraftPerformer!]! tags: [SceneDraftTag!] image: Image fingerprints: [DraftFingerprint!]! } input SceneDraftInput { id: ID title: String code: String details: String director: String url: String @deprecated(reason: "Use urls field instead.") urls: [String!] date: String production_date: String studio: DraftEntityInput performers: [DraftEntityInput!]! tags: [DraftEntityInput!] image: Upload fingerprints: [FingerprintInput!]! } input QueryExistingSceneInput { title: String studio_id: ID fingerprints: [FingerprintInput!]! } type QueryExistingSceneResult { edits: [Edit!]! scenes: [Scene!]! } `, BuiltIn: false}, {Name: "../../graphql/schema/types/site.graphql", Input: `type Site { id: ID! name: String! description: String url: String regex: String valid_types: [ValidSiteTypeEnum!]! icon: String! created: Time! updated: Time! } input SiteCreateInput { name: String! description: String url: String regex: String valid_types: [ValidSiteTypeEnum!]! } input SiteUpdateInput { id: ID! name: String! description: String url: String regex: String valid_types: [ValidSiteTypeEnum!]! } input SiteDestroyInput { id: ID! } type QuerySitesResultType { count: Int! sites: [Site!]! } enum ValidSiteTypeEnum { PERFORMER SCENE STUDIO } `, BuiltIn: false}, {Name: "../../graphql/schema/types/studio.graphql", Input: `type Studio { id: ID! name: String! aliases: [String!]! urls: [URL!]! parent: Studio child_studios: [Studio!]! @deprecated(reason: "Use sub_studios instead") sub_studios(input: StudioQueryInput): QueryStudiosResultType! images: [Image!]! deleted: Boolean! is_favorite: Boolean! created: Time! updated: Time! performers(input: PerformerQueryInput!): QueryPerformersResultType! } input StudioCreateInput { name: String! aliases: [String!] urls: [URLInput!] parent_id: ID image_ids: [ID!] } input StudioUpdateInput { id: ID! name: String aliases: [String!] urls: [URLInput!] parent_id: ID image_ids: [ID!] } input StudioDestroyInput { id: ID! } input StudioEditDetailsInput { name: String aliases: [String!] urls: [URLInput!] parent_id: ID image_ids: [ID!] } input StudioEditInput { edit: EditInput! """Not required for destroy type""" details: StudioEditDetailsInput } type StudioEdit { name: String """Added and modified URLs""" added_urls: [URL!] removed_urls: [URL!] parent: Studio added_images: [Image!] removed_images: [Image!] added_aliases: [String!] removed_aliases: [String!] images: [Image!]! urls: [URL!]! } type QueryStudiosResultType { count: Int! studios: [Studio!]! } enum StudioSortEnum { NAME CREATED_AT UPDATED_AT } input StudioQueryInput { """Filter to search name - assumes like query unless quoted""" name: String """Filter to search studio name, aliases and parent studio name - assumes like query unless quoted""" names: String """Filter to search url - assumes like query unless quoted""" url: String parent: IDCriterionInput has_parent: Boolean """Filter by studio favorite status for the current user""" is_favorite: Boolean page: Int! = 1 per_page: Int! = 25 direction: SortDirectionEnum! = ASC sort: StudioSortEnum! = NAME } `, BuiltIn: false}, {Name: "../../graphql/schema/types/tag.graphql", Input: `enum TagGroupEnum { PEOPLE SCENE ACTION } type Tag { id: ID! name: String! description: String aliases: [String!]! deleted: Boolean! edits: [Edit!]! category: TagCategory created: Time! updated: Time! } input TagCreateInput { name: String! description: String aliases: [String!] category_id: ID } input TagUpdateInput { id: ID! name: String description: String aliases: [String!] category_id: ID } input TagDestroyInput { id: ID! } input TagEditDetailsInput { name: String description: String aliases: [String!] category_id: ID } input TagEditInput { edit: EditInput! """Not required for destroy type""" details: TagEditDetailsInput } type TagEdit { name: String description: String added_aliases: [String!] removed_aliases: [String!] category: TagCategory aliases: [String!]! } type QueryTagsResultType { count: Int! tags: [Tag!]! } type QueryTagCategoriesResultType { count: Int! tag_categories: [TagCategory!]! } enum TagSortEnum { NAME CREATED_AT UPDATED_AT } input TagQueryInput { """Filter to search name, aliases and description - assumes like query unless quoted""" text: String """Searches name and aliases - assumes like query unless quoted""" names: String """Filter to search name - assumes like query unless quoted""" name: String """Filter to category ID""" category_id: ID page: Int! = 1 per_page: Int! = 25 direction: SortDirectionEnum! = ASC sort: TagSortEnum! = NAME } type TagCategory { id: ID! name: String! group: TagGroupEnum! description: String } input TagCategoryCreateInput { name: String! group: TagGroupEnum! description: String } input TagCategoryUpdateInput { id: ID! name: String group: TagGroupEnum description: String } input TagCategoryDestroyInput { id: ID! } `, BuiltIn: false}, {Name: "../../graphql/schema/types/user.graphql", Input: `directive @isUserOwner on FIELD_DEFINITION directive @hasRole(role: RoleEnum!) on FIELD_DEFINITION enum RoleEnum { READ VOTE EDIT MODIFY MODERATE ADMIN """May generate invites without tokens""" INVITE """May grant and rescind invite tokens and resind invite keys""" MANAGE_INVITES BOT READ_ONLY EDIT_TAGS } type InviteKey { id: ID! uses: Int expires: Time } type User { id: ID! name: String! """Should not be visible to other users""" roles: [RoleEnum!] @isUserOwner """Should not be visible to other users""" email: String @isUserOwner """Should not be visible to other users""" api_key: String @isUserOwner notification_subscriptions: [NotificationEnum!]! @isUserOwner """ Vote counts by type """ vote_count: UserVoteCount! """ Edit counts by status """ edit_count: UserEditCount! """Calls to the API from this user over a configurable time period""" api_calls: Int! @isUserOwner invited_by: User @isUserOwner invite_tokens: Int @isUserOwner active_invite_codes: [String!] @isUserOwner @deprecated(reason: "Use invite_codes instead") invite_codes: [InviteKey!] @isUserOwner } input UserCreateInput { name: String! """Password in plain text""" password: String! roles: [RoleEnum!]! email: String! invited_by_id: ID } input UserUpdateInput { id: ID! name: String """Password in plain text""" password: String roles: [RoleEnum!] email: String } input NewUserInput { email: String! invite_key: ID } input ActivateNewUserInput { name: String! activation_key: ID! password: String! } input ResetPasswordInput { email: String! } input UserChangePasswordInput { """Password in plain text""" existing_password: String new_password: String! reset_key: ID } input UserDestroyInput { id: ID! } input GrantInviteInput { user_id: ID! amount: Int! } input RevokeInviteInput { user_id: ID! amount: Int! } type QueryUsersResultType { count: Int! users: [User!]! } input RoleCriterionInput { value: [RoleEnum!]! modifier: CriterionModifier! } input UserQueryInput { """Filter to search user name - assumes like query unless quoted""" name: String """Filter to search email - assumes like query unless quoted""" email: String """Filter by roles""" roles: RoleCriterionInput """Filter by api key""" apiKey: String """Filter by successful edits""" successful_edits: IntCriterionInput """Filter by unsuccessful edits""" unsuccessful_edits: IntCriterionInput """Filter by votes on successful edits""" successful_votes: IntCriterionInput """Filter by votes on unsuccessful edits""" unsuccessful_votes: IntCriterionInput """Filter by number of API calls""" api_calls: IntCriterionInput """Filter by user that invited""" invited_by: ID page: Int! = 1 per_page: Int! = 25 } type UserEditCount { accepted: Int! rejected: Int! pending: Int! immediate_accepted: Int! immediate_rejected: Int! failed: Int! canceled: Int! } type UserVoteCount { abstain: Int! accept: Int! reject: Int! immediate_accept: Int! immediate_reject: Int! } input GenerateInviteCodeInput { # the number of invite keys to generate. If not set, a single invite key will be generated keys: Int # the number of uses for each invite key. If not set, the invite key will have one use uses: Int # the number of seconds until the invite code expires. If not set, the invite code will never expire ttl: Int } input UserChangeEmailInput { existing_email_token: ID new_email_token: ID new_email: String } enum UserChangeEmailStatus { CONFIRM_OLD CONFIRM_NEW EXPIRED INVALID_TOKEN SUCCESS ERROR } `, BuiltIn: false}, {Name: "../../graphql/schema/types/version.graphql", Input: `type Version { hash: String! build_time: String! build_type: String! version: String! } `, BuiltIn: false}, {Name: "../../graphql/schema/schema.graphql", Input: `"""The query root for this schema""" type Query { #### Performers #### # performer names may not be unique """Find a performer by ID""" findPerformer(id: ID!): Performer @hasRole(role: READ) queryPerformers(input: PerformerQueryInput!): QueryPerformersResultType! @hasRole(role: READ) #### Studios #### # studio names should be unique """Find a studio by ID or name""" findStudio(id: ID, name: String): Studio @hasRole(role: READ) queryStudios(input: StudioQueryInput!): QueryStudiosResultType! @hasRole(role: READ) #### Tags #### # tag names will be unique """Find a tag by ID or name""" findTag(id: ID, name: String): Tag @hasRole(role: READ) """Find a tag with a matching name or alias""" findTagOrAlias(name: String!): Tag @hasRole(role: READ) queryTags(input: TagQueryInput!): QueryTagsResultType! @hasRole(role: READ) """Find a tag category by ID""" findTagCategory(id: ID!): TagCategory @hasRole(role: READ) queryTagCategories: QueryTagCategoriesResultType! @hasRole(role: READ) #### Scenes #### # ids should be unique """Find a scene by ID""" findScene(id: ID!): Scene @hasRole(role: READ) """Finds scenes that match a list of hashes""" findScenesBySceneFingerprints(fingerprints: [[FingerprintQueryInput!]!]!): [[Scene]!]! @hasRole(role: READ) queryScenes(input: SceneQueryInput!): QueryScenesResultType! @hasRole(role: READ) """Find an external site by ID""" findSite(id: ID!): Site @hasRole(role: READ) querySites: QuerySitesResultType! @hasRole(role: READ) #### Edits #### findEdit(id: ID!): Edit @hasRole(role: READ) queryEdits(input: EditQueryInput!): QueryEditsResultType! @hasRole(role: READ) #### Users #### """Find user by ID or username""" findUser(id: ID, username: String): User @hasRole(role: READ) queryUsers(input: UserQueryInput!): QueryUsersResultType! @hasRole(role: ADMIN) """Returns currently authenticated user""" me: User ### Full text search ### searchPerformer(term: String!, limit: Int): [Performer!]! @hasRole(role: READ) @deprecated(reason: "Use searchPerformers") searchPerformers(term: String!, limit: Int, page: Int, per_page: Int, filter: PerformerSearchFilter): QueryPerformersResultType! @hasRole(role: READ) searchScene(term: String!, limit: Int): [Scene!]! @hasRole(role: READ) @deprecated(reason: "Use searchScenes") searchScenes(term: String!, limit: Int, page: Int, per_page: Int): QueryScenesResultType! @hasRole(role: READ) searchTag(term: String!, limit: Int): [Tag!]! @hasRole(role: READ) searchStudio(term: String!, limit: Int): [Studio!]! @hasRole(role: READ) ### Drafts ### findDraft(id: ID!): Draft @hasRole(role: READ) findDrafts: [Draft!]! @hasRole(role: READ) ###Find scenes or pending scenes which match scene input### queryExistingScene(input: QueryExistingSceneInput!): QueryExistingSceneResult! @hasRole(role: READ) ###Find performers or pending performers which match performer input### queryExistingPerformer(input: QueryExistingPerformerInput!): QueryExistingPerformerResult! @hasRole(role: READ) #### Version #### version: Version! @hasRole(role: READ) ### Instance Config ### getConfig: StashBoxConfig! queryNotifications(input: QueryNotificationsInput!): QueryNotificationsResult! @hasRole(role: READ) getUnreadNotificationCount: Int! @hasRole(role: READ) ### Moderator Audits ### queryModAudits(input: ModAuditQueryInput!): QueryModAuditsResultType! @hasRole(role: ADMIN) } type Mutation { # Admin-only interface sceneCreate(input: SceneCreateInput!): Scene @hasRole(role: MODIFY) sceneUpdate(input: SceneUpdateInput!): Scene @hasRole(role: MODIFY) sceneDestroy(input: SceneDestroyInput!): Boolean! @hasRole(role: MODIFY) performerCreate(input: PerformerCreateInput!): Performer @hasRole(role: MODIFY) performerUpdate(input: PerformerUpdateInput!): Performer @hasRole(role: MODIFY) performerDestroy(input: PerformerDestroyInput!): Boolean! @hasRole(role: MODIFY) studioCreate(input: StudioCreateInput!): Studio @hasRole(role: MODIFY) studioUpdate(input: StudioUpdateInput!): Studio @hasRole(role: MODIFY) studioDestroy(input: StudioDestroyInput!): Boolean! @hasRole(role: MODIFY) tagCreate(input: TagCreateInput!): Tag @hasRole(role: MODIFY) tagUpdate(input: TagUpdateInput!): Tag @hasRole(role: MODIFY) tagDestroy(input: TagDestroyInput!): Boolean! @hasRole(role: MODIFY) userCreate(input: UserCreateInput!): User @hasRole(role: ADMIN) userUpdate(input: UserUpdateInput!): User @hasRole(role: ADMIN) userDestroy(input: UserDestroyInput!): Boolean! @hasRole(role: ADMIN) imageCreate(input: ImageCreateInput!): Image @hasRole(role: EDIT) imageDestroy(input: ImageDestroyInput!): Boolean! @hasRole(role: MODIFY) """User interface for registering""" newUser(input: NewUserInput!): ID activateNewUser(input: ActivateNewUserInput!): User generateInviteCode: ID @deprecated(reason: "Use generateInviteCodes") """Generates an invite code using an invite token""" generateInviteCodes(input: GenerateInviteCodeInput): [ID!]! """Removes a pending invite code - refunding the token""" rescindInviteCode(code: ID!): Boolean! """Adds invite tokens for a user""" grantInvite(input: GrantInviteInput!): Int! """Removes invite tokens from a user""" revokeInvite(input: RevokeInviteInput!): Int! tagCategoryCreate(input: TagCategoryCreateInput!): TagCategory @hasRole(role: ADMIN) tagCategoryUpdate(input: TagCategoryUpdateInput!): TagCategory @hasRole(role: ADMIN) tagCategoryDestroy(input: TagCategoryDestroyInput!): Boolean! @hasRole(role: ADMIN) siteCreate(input: SiteCreateInput!): Site @hasRole(role: ADMIN) siteUpdate(input: SiteUpdateInput!): Site @hasRole(role: ADMIN) siteDestroy(input: SiteDestroyInput!): Boolean! @hasRole(role: ADMIN) """Regenerates the api key for the given user, or the current user if id not provided""" regenerateAPIKey(userID: ID): String! """Generates an email to reset a user password""" resetPassword(input: ResetPasswordInput!): Boolean! """Changes the password for the current user""" changePassword(input: UserChangePasswordInput!): Boolean! """Request an email change for the current user""" requestChangeEmail: UserChangeEmailStatus! @hasRole(role: READ) validateChangeEmail(token: ID!, email: String!): UserChangeEmailStatus! @hasRole(role: READ) confirmChangeEmail(token: ID!): UserChangeEmailStatus! @hasRole(role: READ) # Edit interfaces """Propose a new scene or modification to a scene""" sceneEdit(input: SceneEditInput!): Edit! @hasRole(role: EDIT) """Propose a new performer or modification to a performer""" performerEdit(input: PerformerEditInput!): Edit! @hasRole(role: EDIT) """Propose a new studio or modification to a studio""" studioEdit(input: StudioEditInput!): Edit! @hasRole(role: EDIT) """Propose a new tag or modification to a tag""" tagEdit(input: TagEditInput!): Edit! @hasRole(role: EDIT) """Update a pending scene edit""" sceneEditUpdate(id: ID!, input: SceneEditInput!): Edit! @hasRole(role: EDIT) """Update a pending performer edit""" performerEditUpdate(id: ID!, input: PerformerEditInput!): Edit! @hasRole(role: EDIT) """Update a pending studio edit""" studioEditUpdate(id: ID!, input: StudioEditInput!): Edit! @hasRole(role: EDIT) """Update a pending tag edit""" tagEditUpdate(id: ID!, input: TagEditInput!): Edit! @hasRole(role: EDIT) """Vote to accept/reject an edit""" editVote(input: EditVoteInput!): Edit! @hasRole(role: VOTE) """Comment on an edit""" editComment(input: EditCommentInput!): Edit! @hasRole(role: EDIT) """Apply edit without voting""" applyEdit(input: ApplyEditInput!): Edit! @hasRole(role: ADMIN) """Cancel edit without voting""" cancelEdit(input: CancelEditInput!): Edit! @hasRole(role: EDIT) """Delete a closed edit - moderator only""" deleteEdit(input: DeleteEditInput!): Boolean! @hasRole(role: MODERATE) """Amend a closed edit by removing fields - moderator only""" amendEdit(input: AmendEditInput!): Edit! @hasRole(role: MODERATE) """Matches/unmatches a scene to fingerprint""" submitFingerprint(input: FingerprintSubmission!): Boolean! @hasRole(role: READ) """Batch submit up to 1000 fingerprint matches""" submitFingerprints(input: [FingerprintBatchSubmission!]!): [FingerprintSubmissionResult!]! @hasRole(role: READ) """Move all fingerprint submissions from source scene to target scene""" sceneMoveFingerprintSubmissions(input: MoveFingerprintSubmissionsInput!): Boolean! @hasRole(role: MODERATE) """Delete all fingerprint submissions for a specific fingerprint on a scene""" sceneDeleteFingerprintSubmissions(input: DeleteFingerprintSubmissionsInput!): Boolean! @hasRole(role: MODERATE) """Draft submissions""" submitSceneDraft(input: SceneDraftInput!): DraftSubmissionStatus! @hasRole(role: EDIT) submitPerformerDraft(input: PerformerDraftInput!): DraftSubmissionStatus! @hasRole(role: EDIT) destroyDraft(id: ID!): Boolean! @hasRole(role: EDIT) """Favorite or unfavorite a performer""" favoritePerformer(id: ID!, favorite: Boolean!): Boolean! @hasRole(role: READ) """Favorite or unfavorite a studio""" favoriteStudio(id: ID!, favorite: Boolean!): Boolean! @hasRole(role: READ) """Mark all of the current users notifications as read.""" markNotificationsRead(notification: MarkNotificationReadInput): Boolean! @hasRole(role: READ) """Update notification subscriptions for current user.""" updateNotificationSubscriptions(subscriptions: [NotificationEnum!]!): Boolean! @hasRole(role: READ) } schema { query: Query mutation: Mutation } `, BuiltIn: false}, } var parsedSchema = gqlparser.MustLoadSchema(sources...) // endregion ************************** generated!.gotpl ************************** // region ***************************** args.gotpl ***************************** func (ec *executionContext) dir_hasRole_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "role", ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum) if err != nil { return nil, err } args["role"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_activateNewUser_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNActivateNewUserInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐActivateNewUserInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_amendEdit_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNAmendEditInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐAmendEditInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_applyEdit_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNApplyEditInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐApplyEditInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_cancelEdit_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNCancelEditInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐCancelEditInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_changePassword_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNUserChangePasswordInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUserChangePasswordInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_confirmChangeEmail_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "token", ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID) if err != nil { return nil, err } args["token"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_deleteEdit_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNDeleteEditInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDeleteEditInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_destroyDraft_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "id", ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID) if err != nil { return nil, err } args["id"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_editComment_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNEditCommentInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditCommentInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_editVote_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNEditVoteInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditVoteInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_favoritePerformer_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "id", ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID) if err != nil { return nil, err } args["id"] = arg0 arg1, err := graphql.ProcessArgField(ctx, rawArgs, "favorite", ec.unmarshalNBoolean2bool) if err != nil { return nil, err } args["favorite"] = arg1 return args, nil } func (ec *executionContext) field_Mutation_favoriteStudio_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "id", ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID) if err != nil { return nil, err } args["id"] = arg0 arg1, err := graphql.ProcessArgField(ctx, rawArgs, "favorite", ec.unmarshalNBoolean2bool) if err != nil { return nil, err } args["favorite"] = arg1 return args, nil } func (ec *executionContext) field_Mutation_generateInviteCodes_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalOGenerateInviteCodeInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐGenerateInviteCodeInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_grantInvite_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNGrantInviteInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐGrantInviteInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_imageCreate_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNImageCreateInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐImageCreateInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_imageDestroy_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNImageDestroyInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐImageDestroyInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_markNotificationsRead_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "notification", ec.unmarshalOMarkNotificationReadInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐMarkNotificationReadInput) if err != nil { return nil, err } args["notification"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_newUser_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNNewUserInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐNewUserInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_performerCreate_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNPerformerCreateInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerCreateInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_performerDestroy_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNPerformerDestroyInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerDestroyInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_performerEditUpdate_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "id", ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID) if err != nil { return nil, err } args["id"] = arg0 arg1, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNPerformerEditInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerEditInput) if err != nil { return nil, err } args["input"] = arg1 return args, nil } func (ec *executionContext) field_Mutation_performerEdit_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNPerformerEditInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerEditInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_performerUpdate_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNPerformerUpdateInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerUpdateInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_regenerateAPIKey_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "userID", ec.unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID) if err != nil { return nil, err } args["userID"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_rescindInviteCode_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "code", ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID) if err != nil { return nil, err } args["code"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_resetPassword_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNResetPasswordInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐResetPasswordInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_revokeInvite_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNRevokeInviteInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRevokeInviteInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_sceneCreate_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNSceneCreateInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneCreateInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_sceneDeleteFingerprintSubmissions_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNDeleteFingerprintSubmissionsInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDeleteFingerprintSubmissionsInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_sceneDestroy_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNSceneDestroyInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneDestroyInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_sceneEditUpdate_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "id", ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID) if err != nil { return nil, err } args["id"] = arg0 arg1, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNSceneEditInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneEditInput) if err != nil { return nil, err } args["input"] = arg1 return args, nil } func (ec *executionContext) field_Mutation_sceneEdit_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNSceneEditInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneEditInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_sceneMoveFingerprintSubmissions_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNMoveFingerprintSubmissionsInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐMoveFingerprintSubmissionsInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_sceneUpdate_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNSceneUpdateInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneUpdateInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_siteCreate_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNSiteCreateInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSiteCreateInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_siteDestroy_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNSiteDestroyInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSiteDestroyInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_siteUpdate_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNSiteUpdateInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSiteUpdateInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_studioCreate_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNStudioCreateInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStudioCreateInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_studioDestroy_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNStudioDestroyInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStudioDestroyInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_studioEditUpdate_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "id", ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID) if err != nil { return nil, err } args["id"] = arg0 arg1, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNStudioEditInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStudioEditInput) if err != nil { return nil, err } args["input"] = arg1 return args, nil } func (ec *executionContext) field_Mutation_studioEdit_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNStudioEditInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStudioEditInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_studioUpdate_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNStudioUpdateInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStudioUpdateInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_submitFingerprint_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNFingerprintSubmission2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintSubmission) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_submitFingerprints_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNFingerprintBatchSubmission2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintBatchSubmissionᚄ) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_submitPerformerDraft_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNPerformerDraftInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerDraftInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_submitSceneDraft_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNSceneDraftInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneDraftInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_tagCategoryCreate_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNTagCategoryCreateInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagCategoryCreateInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_tagCategoryDestroy_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNTagCategoryDestroyInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagCategoryDestroyInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_tagCategoryUpdate_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNTagCategoryUpdateInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagCategoryUpdateInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_tagCreate_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNTagCreateInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagCreateInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_tagDestroy_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNTagDestroyInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagDestroyInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_tagEditUpdate_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "id", ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID) if err != nil { return nil, err } args["id"] = arg0 arg1, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNTagEditInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagEditInput) if err != nil { return nil, err } args["input"] = arg1 return args, nil } func (ec *executionContext) field_Mutation_tagEdit_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNTagEditInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagEditInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_tagUpdate_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNTagUpdateInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagUpdateInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_updateNotificationSubscriptions_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "subscriptions", ec.unmarshalNNotificationEnum2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐNotificationEnumᚄ) if err != nil { return nil, err } args["subscriptions"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_userCreate_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNUserCreateInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUserCreateInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_userDestroy_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNUserDestroyInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUserDestroyInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_userUpdate_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNUserUpdateInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUserUpdateInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Mutation_validateChangeEmail_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "token", ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID) if err != nil { return nil, err } args["token"] = arg0 arg1, err := graphql.ProcessArgField(ctx, rawArgs, "email", ec.unmarshalNString2string) if err != nil { return nil, err } args["email"] = arg1 return args, nil } func (ec *executionContext) field_Performer_scenes_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalOPerformerScenesInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerScenesInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Performer_studios_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "studio_id", ec.unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID) if err != nil { return nil, err } args["studio_id"] = arg0 return args, nil } func (ec *executionContext) field_Query___type_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "name", ec.unmarshalNString2string) if err != nil { return nil, err } args["name"] = arg0 return args, nil } func (ec *executionContext) field_Query_findDraft_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "id", ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID) if err != nil { return nil, err } args["id"] = arg0 return args, nil } func (ec *executionContext) field_Query_findEdit_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "id", ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID) if err != nil { return nil, err } args["id"] = arg0 return args, nil } func (ec *executionContext) field_Query_findPerformer_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "id", ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID) if err != nil { return nil, err } args["id"] = arg0 return args, nil } func (ec *executionContext) field_Query_findScene_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "id", ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID) if err != nil { return nil, err } args["id"] = arg0 return args, nil } func (ec *executionContext) field_Query_findScenesBySceneFingerprints_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "fingerprints", ec.unmarshalNFingerprintQueryInput2ᚕᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintQueryInputᚄ) if err != nil { return nil, err } args["fingerprints"] = arg0 return args, nil } func (ec *executionContext) field_Query_findSite_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "id", ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID) if err != nil { return nil, err } args["id"] = arg0 return args, nil } func (ec *executionContext) field_Query_findStudio_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "id", ec.unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID) if err != nil { return nil, err } args["id"] = arg0 arg1, err := graphql.ProcessArgField(ctx, rawArgs, "name", ec.unmarshalOString2ᚖstring) if err != nil { return nil, err } args["name"] = arg1 return args, nil } func (ec *executionContext) field_Query_findTagCategory_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "id", ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID) if err != nil { return nil, err } args["id"] = arg0 return args, nil } func (ec *executionContext) field_Query_findTagOrAlias_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "name", ec.unmarshalNString2string) if err != nil { return nil, err } args["name"] = arg0 return args, nil } func (ec *executionContext) field_Query_findTag_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "id", ec.unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID) if err != nil { return nil, err } args["id"] = arg0 arg1, err := graphql.ProcessArgField(ctx, rawArgs, "name", ec.unmarshalOString2ᚖstring) if err != nil { return nil, err } args["name"] = arg1 return args, nil } func (ec *executionContext) field_Query_findUser_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "id", ec.unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID) if err != nil { return nil, err } args["id"] = arg0 arg1, err := graphql.ProcessArgField(ctx, rawArgs, "username", ec.unmarshalOString2ᚖstring) if err != nil { return nil, err } args["username"] = arg1 return args, nil } func (ec *executionContext) field_Query_queryEdits_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNEditQueryInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditQueryInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Query_queryExistingPerformer_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNQueryExistingPerformerInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐQueryExistingPerformerInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Query_queryExistingScene_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNQueryExistingSceneInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐQueryExistingSceneInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Query_queryModAudits_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNModAuditQueryInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐModAuditQueryInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Query_queryNotifications_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNQueryNotificationsInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐQueryNotificationsInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Query_queryPerformers_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNPerformerQueryInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerQueryInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Query_queryScenes_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNSceneQueryInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneQueryInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Query_queryStudios_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNStudioQueryInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStudioQueryInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Query_queryTags_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNTagQueryInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagQueryInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Query_queryUsers_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNUserQueryInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUserQueryInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Query_searchPerformer_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "term", ec.unmarshalNString2string) if err != nil { return nil, err } args["term"] = arg0 arg1, err := graphql.ProcessArgField(ctx, rawArgs, "limit", ec.unmarshalOInt2ᚖint) if err != nil { return nil, err } args["limit"] = arg1 return args, nil } func (ec *executionContext) field_Query_searchPerformers_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "term", ec.unmarshalNString2string) if err != nil { return nil, err } args["term"] = arg0 arg1, err := graphql.ProcessArgField(ctx, rawArgs, "limit", ec.unmarshalOInt2ᚖint) if err != nil { return nil, err } args["limit"] = arg1 arg2, err := graphql.ProcessArgField(ctx, rawArgs, "page", ec.unmarshalOInt2ᚖint) if err != nil { return nil, err } args["page"] = arg2 arg3, err := graphql.ProcessArgField(ctx, rawArgs, "per_page", ec.unmarshalOInt2ᚖint) if err != nil { return nil, err } args["per_page"] = arg3 arg4, err := graphql.ProcessArgField(ctx, rawArgs, "filter", ec.unmarshalOPerformerSearchFilter2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerSearchFilter) if err != nil { return nil, err } args["filter"] = arg4 return args, nil } func (ec *executionContext) field_Query_searchScene_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "term", ec.unmarshalNString2string) if err != nil { return nil, err } args["term"] = arg0 arg1, err := graphql.ProcessArgField(ctx, rawArgs, "limit", ec.unmarshalOInt2ᚖint) if err != nil { return nil, err } args["limit"] = arg1 return args, nil } func (ec *executionContext) field_Query_searchScenes_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "term", ec.unmarshalNString2string) if err != nil { return nil, err } args["term"] = arg0 arg1, err := graphql.ProcessArgField(ctx, rawArgs, "limit", ec.unmarshalOInt2ᚖint) if err != nil { return nil, err } args["limit"] = arg1 arg2, err := graphql.ProcessArgField(ctx, rawArgs, "page", ec.unmarshalOInt2ᚖint) if err != nil { return nil, err } args["page"] = arg2 arg3, err := graphql.ProcessArgField(ctx, rawArgs, "per_page", ec.unmarshalOInt2ᚖint) if err != nil { return nil, err } args["per_page"] = arg3 return args, nil } func (ec *executionContext) field_Query_searchStudio_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "term", ec.unmarshalNString2string) if err != nil { return nil, err } args["term"] = arg0 arg1, err := graphql.ProcessArgField(ctx, rawArgs, "limit", ec.unmarshalOInt2ᚖint) if err != nil { return nil, err } args["limit"] = arg1 return args, nil } func (ec *executionContext) field_Query_searchTag_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "term", ec.unmarshalNString2string) if err != nil { return nil, err } args["term"] = arg0 arg1, err := graphql.ProcessArgField(ctx, rawArgs, "limit", ec.unmarshalOInt2ᚖint) if err != nil { return nil, err } args["limit"] = arg1 return args, nil } func (ec *executionContext) field_Scene_fingerprints_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "is_submitted", ec.unmarshalOBoolean2ᚖbool) if err != nil { return nil, err } args["is_submitted"] = arg0 return args, nil } func (ec *executionContext) field_Studio_performers_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNPerformerQueryInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerQueryInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field_Studio_sub_studios_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalOStudioQueryInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStudioQueryInput) if err != nil { return nil, err } args["input"] = arg0 return args, nil } func (ec *executionContext) field___Directive_args_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "includeDeprecated", ec.unmarshalOBoolean2ᚖbool) if err != nil { return nil, err } args["includeDeprecated"] = arg0 return args, nil } func (ec *executionContext) field___Field_args_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "includeDeprecated", ec.unmarshalOBoolean2ᚖbool) if err != nil { return nil, err } args["includeDeprecated"] = arg0 return args, nil } func (ec *executionContext) field___Type_enumValues_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "includeDeprecated", ec.unmarshalOBoolean2bool) if err != nil { return nil, err } args["includeDeprecated"] = arg0 return args, nil } func (ec *executionContext) field___Type_fields_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} arg0, err := graphql.ProcessArgField(ctx, rawArgs, "includeDeprecated", ec.unmarshalOBoolean2bool) if err != nil { return nil, err } args["includeDeprecated"] = arg0 return args, nil } // endregion ***************************** args.gotpl ***************************** // region ************************** directives.gotpl ************************** // endregion ************************** directives.gotpl ************************** // region **************************** field.gotpl ***************************** func (ec *executionContext) _BodyModification_location(ctx context.Context, field graphql.CollectedField, obj *BodyModification) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_BodyModification_location, func(ctx context.Context) (any, error) { return obj.Location, nil }, nil, ec.marshalNString2string, true, true, ) } func (ec *executionContext) fieldContext_BodyModification_location(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "BodyModification", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _BodyModification_description(ctx context.Context, field graphql.CollectedField, obj *BodyModification) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_BodyModification_description, func(ctx context.Context) (any, error) { return obj.Description, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_BodyModification_description(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "BodyModification", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _CommentCommentedEdit_comment(ctx context.Context, field graphql.CollectedField, obj *CommentCommentedEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_CommentCommentedEdit_comment, func(ctx context.Context) (any, error) { return obj.Comment, nil }, nil, ec.marshalNEditComment2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditComment, true, true, ) } func (ec *executionContext) fieldContext_CommentCommentedEdit_comment(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "CommentCommentedEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_EditComment_id(ctx, field) case "user": return ec.fieldContext_EditComment_user(ctx, field) case "date": return ec.fieldContext_EditComment_date(ctx, field) case "comment": return ec.fieldContext_EditComment_comment(ctx, field) case "edit": return ec.fieldContext_EditComment_edit(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type EditComment", field.Name) }, } return fc, nil } func (ec *executionContext) _CommentOwnEdit_comment(ctx context.Context, field graphql.CollectedField, obj *CommentOwnEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_CommentOwnEdit_comment, func(ctx context.Context) (any, error) { return obj.Comment, nil }, nil, ec.marshalNEditComment2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditComment, true, true, ) } func (ec *executionContext) fieldContext_CommentOwnEdit_comment(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "CommentOwnEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_EditComment_id(ctx, field) case "user": return ec.fieldContext_EditComment_user(ctx, field) case "date": return ec.fieldContext_EditComment_date(ctx, field) case "comment": return ec.fieldContext_EditComment_comment(ctx, field) case "edit": return ec.fieldContext_EditComment_edit(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type EditComment", field.Name) }, } return fc, nil } func (ec *executionContext) _CommentVotedEdit_comment(ctx context.Context, field graphql.CollectedField, obj *CommentVotedEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_CommentVotedEdit_comment, func(ctx context.Context) (any, error) { return obj.Comment, nil }, nil, ec.marshalNEditComment2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditComment, true, true, ) } func (ec *executionContext) fieldContext_CommentVotedEdit_comment(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "CommentVotedEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_EditComment_id(ctx, field) case "user": return ec.fieldContext_EditComment_user(ctx, field) case "date": return ec.fieldContext_EditComment_date(ctx, field) case "comment": return ec.fieldContext_EditComment_comment(ctx, field) case "edit": return ec.fieldContext_EditComment_edit(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type EditComment", field.Name) }, } return fc, nil } func (ec *executionContext) _DownvoteOwnEdit_edit(ctx context.Context, field graphql.CollectedField, obj *DownvoteOwnEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_DownvoteOwnEdit_edit, func(ctx context.Context) (any, error) { return obj.Edit, nil }, nil, ec.marshalNEdit2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEdit, true, true, ) } func (ec *executionContext) fieldContext_DownvoteOwnEdit_edit(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "DownvoteOwnEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Edit_id(ctx, field) case "user": return ec.fieldContext_Edit_user(ctx, field) case "target": return ec.fieldContext_Edit_target(ctx, field) case "target_type": return ec.fieldContext_Edit_target_type(ctx, field) case "merge_sources": return ec.fieldContext_Edit_merge_sources(ctx, field) case "operation": return ec.fieldContext_Edit_operation(ctx, field) case "bot": return ec.fieldContext_Edit_bot(ctx, field) case "details": return ec.fieldContext_Edit_details(ctx, field) case "old_details": return ec.fieldContext_Edit_old_details(ctx, field) case "options": return ec.fieldContext_Edit_options(ctx, field) case "comments": return ec.fieldContext_Edit_comments(ctx, field) case "votes": return ec.fieldContext_Edit_votes(ctx, field) case "vote_count": return ec.fieldContext_Edit_vote_count(ctx, field) case "destructive": return ec.fieldContext_Edit_destructive(ctx, field) case "status": return ec.fieldContext_Edit_status(ctx, field) case "applied": return ec.fieldContext_Edit_applied(ctx, field) case "update_count": return ec.fieldContext_Edit_update_count(ctx, field) case "updatable": return ec.fieldContext_Edit_updatable(ctx, field) case "created": return ec.fieldContext_Edit_created(ctx, field) case "updated": return ec.fieldContext_Edit_updated(ctx, field) case "closed": return ec.fieldContext_Edit_closed(ctx, field) case "expires": return ec.fieldContext_Edit_expires(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Edit", field.Name) }, } return fc, nil } func (ec *executionContext) _Draft_id(ctx context.Context, field graphql.CollectedField, obj *Draft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Draft_id, func(ctx context.Context) (any, error) { return obj.ID, nil }, nil, ec.marshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID, true, true, ) } func (ec *executionContext) fieldContext_Draft_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Draft", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type ID does not have child fields") }, } return fc, nil } func (ec *executionContext) _Draft_created(ctx context.Context, field graphql.CollectedField, obj *Draft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Draft_created, func(ctx context.Context) (any, error) { return ec.Resolvers.Draft().Created(ctx, obj) }, nil, ec.marshalNTime2ᚖtimeᚐTime, true, true, ) } func (ec *executionContext) fieldContext_Draft_created(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Draft", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Time does not have child fields") }, } return fc, nil } func (ec *executionContext) _Draft_expires(ctx context.Context, field graphql.CollectedField, obj *Draft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Draft_expires, func(ctx context.Context) (any, error) { return ec.Resolvers.Draft().Expires(ctx, obj) }, nil, ec.marshalNTime2ᚖtimeᚐTime, true, true, ) } func (ec *executionContext) fieldContext_Draft_expires(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Draft", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Time does not have child fields") }, } return fc, nil } func (ec *executionContext) _Draft_data(ctx context.Context, field graphql.CollectedField, obj *Draft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Draft_data, func(ctx context.Context) (any, error) { return ec.Resolvers.Draft().Data(ctx, obj) }, nil, ec.marshalNDraftData2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDraftData, true, true, ) } func (ec *executionContext) fieldContext_Draft_data(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Draft", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type DraftData does not have child fields") }, } return fc, nil } func (ec *executionContext) _DraftEntity_name(ctx context.Context, field graphql.CollectedField, obj *DraftEntity) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_DraftEntity_name, func(ctx context.Context) (any, error) { return obj.Name, nil }, nil, ec.marshalNString2string, true, true, ) } func (ec *executionContext) fieldContext_DraftEntity_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "DraftEntity", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _DraftEntity_id(ctx context.Context, field graphql.CollectedField, obj *DraftEntity) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_DraftEntity_id, func(ctx context.Context) (any, error) { return obj.ID, nil }, nil, ec.marshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID, true, false, ) } func (ec *executionContext) fieldContext_DraftEntity_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "DraftEntity", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type ID does not have child fields") }, } return fc, nil } func (ec *executionContext) _DraftFingerprint_hash(ctx context.Context, field graphql.CollectedField, obj *DraftFingerprint) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_DraftFingerprint_hash, func(ctx context.Context) (any, error) { return obj.Hash, nil }, nil, ec.marshalNFingerprintHash2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintHash, true, true, ) } func (ec *executionContext) fieldContext_DraftFingerprint_hash(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "DraftFingerprint", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type FingerprintHash does not have child fields") }, } return fc, nil } func (ec *executionContext) _DraftFingerprint_algorithm(ctx context.Context, field graphql.CollectedField, obj *DraftFingerprint) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_DraftFingerprint_algorithm, func(ctx context.Context) (any, error) { return obj.Algorithm, nil }, nil, ec.marshalNFingerprintAlgorithm2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintAlgorithm, true, true, ) } func (ec *executionContext) fieldContext_DraftFingerprint_algorithm(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "DraftFingerprint", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type FingerprintAlgorithm does not have child fields") }, } return fc, nil } func (ec *executionContext) _DraftFingerprint_duration(ctx context.Context, field graphql.CollectedField, obj *DraftFingerprint) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_DraftFingerprint_duration, func(ctx context.Context) (any, error) { return obj.Duration, nil }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_DraftFingerprint_duration(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "DraftFingerprint", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _DraftSubmissionStatus_id(ctx context.Context, field graphql.CollectedField, obj *DraftSubmissionStatus) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_DraftSubmissionStatus_id, func(ctx context.Context) (any, error) { return obj.ID, nil }, nil, ec.marshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID, true, false, ) } func (ec *executionContext) fieldContext_DraftSubmissionStatus_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "DraftSubmissionStatus", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type ID does not have child fields") }, } return fc, nil } func (ec *executionContext) _Edit_id(ctx context.Context, field graphql.CollectedField, obj *Edit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Edit_id, func(ctx context.Context) (any, error) { return obj.ID, nil }, nil, ec.marshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID, true, true, ) } func (ec *executionContext) fieldContext_Edit_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Edit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type ID does not have child fields") }, } return fc, nil } func (ec *executionContext) _Edit_user(ctx context.Context, field graphql.CollectedField, obj *Edit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Edit_user, func(ctx context.Context) (any, error) { return ec.Resolvers.Edit().User(ctx, obj) }, nil, ec.marshalOUser2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUser, true, false, ) } func (ec *executionContext) fieldContext_Edit_user(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Edit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_User_id(ctx, field) case "name": return ec.fieldContext_User_name(ctx, field) case "roles": return ec.fieldContext_User_roles(ctx, field) case "email": return ec.fieldContext_User_email(ctx, field) case "api_key": return ec.fieldContext_User_api_key(ctx, field) case "notification_subscriptions": return ec.fieldContext_User_notification_subscriptions(ctx, field) case "vote_count": return ec.fieldContext_User_vote_count(ctx, field) case "edit_count": return ec.fieldContext_User_edit_count(ctx, field) case "api_calls": return ec.fieldContext_User_api_calls(ctx, field) case "invited_by": return ec.fieldContext_User_invited_by(ctx, field) case "invite_tokens": return ec.fieldContext_User_invite_tokens(ctx, field) case "active_invite_codes": return ec.fieldContext_User_active_invite_codes(ctx, field) case "invite_codes": return ec.fieldContext_User_invite_codes(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type User", field.Name) }, } return fc, nil } func (ec *executionContext) _Edit_target(ctx context.Context, field graphql.CollectedField, obj *Edit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Edit_target, func(ctx context.Context) (any, error) { return ec.Resolvers.Edit().Target(ctx, obj) }, nil, ec.marshalOEditTarget2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditTarget, true, false, ) } func (ec *executionContext) fieldContext_Edit_target(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Edit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type EditTarget does not have child fields") }, } return fc, nil } func (ec *executionContext) _Edit_target_type(ctx context.Context, field graphql.CollectedField, obj *Edit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Edit_target_type, func(ctx context.Context) (any, error) { return ec.Resolvers.Edit().TargetType(ctx, obj) }, nil, ec.marshalNTargetTypeEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTargetTypeEnum, true, true, ) } func (ec *executionContext) fieldContext_Edit_target_type(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Edit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type TargetTypeEnum does not have child fields") }, } return fc, nil } func (ec *executionContext) _Edit_merge_sources(ctx context.Context, field graphql.CollectedField, obj *Edit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Edit_merge_sources, func(ctx context.Context) (any, error) { return ec.Resolvers.Edit().MergeSources(ctx, obj) }, nil, ec.marshalNEditTarget2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditTargetᚄ, true, true, ) } func (ec *executionContext) fieldContext_Edit_merge_sources(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Edit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type EditTarget does not have child fields") }, } return fc, nil } func (ec *executionContext) _Edit_operation(ctx context.Context, field graphql.CollectedField, obj *Edit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Edit_operation, func(ctx context.Context) (any, error) { return ec.Resolvers.Edit().Operation(ctx, obj) }, nil, ec.marshalNOperationEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐOperationEnum, true, true, ) } func (ec *executionContext) fieldContext_Edit_operation(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Edit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type OperationEnum does not have child fields") }, } return fc, nil } func (ec *executionContext) _Edit_bot(ctx context.Context, field graphql.CollectedField, obj *Edit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Edit_bot, func(ctx context.Context) (any, error) { return obj.Bot, nil }, nil, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_Edit_bot(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Edit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } return fc, nil } func (ec *executionContext) _Edit_details(ctx context.Context, field graphql.CollectedField, obj *Edit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Edit_details, func(ctx context.Context) (any, error) { return ec.Resolvers.Edit().Details(ctx, obj) }, nil, ec.marshalOEditDetails2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditDetails, true, false, ) } func (ec *executionContext) fieldContext_Edit_details(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Edit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type EditDetails does not have child fields") }, } return fc, nil } func (ec *executionContext) _Edit_old_details(ctx context.Context, field graphql.CollectedField, obj *Edit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Edit_old_details, func(ctx context.Context) (any, error) { return ec.Resolvers.Edit().OldDetails(ctx, obj) }, nil, ec.marshalOEditDetails2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditDetails, true, false, ) } func (ec *executionContext) fieldContext_Edit_old_details(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Edit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type EditDetails does not have child fields") }, } return fc, nil } func (ec *executionContext) _Edit_options(ctx context.Context, field graphql.CollectedField, obj *Edit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Edit_options, func(ctx context.Context) (any, error) { return ec.Resolvers.Edit().Options(ctx, obj) }, nil, ec.marshalOPerformerEditOptions2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerEditOptions, true, false, ) } func (ec *executionContext) fieldContext_Edit_options(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Edit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "set_modify_aliases": return ec.fieldContext_PerformerEditOptions_set_modify_aliases(ctx, field) case "set_merge_aliases": return ec.fieldContext_PerformerEditOptions_set_merge_aliases(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type PerformerEditOptions", field.Name) }, } return fc, nil } func (ec *executionContext) _Edit_comments(ctx context.Context, field graphql.CollectedField, obj *Edit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Edit_comments, func(ctx context.Context) (any, error) { return ec.Resolvers.Edit().Comments(ctx, obj) }, nil, ec.marshalNEditComment2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditCommentᚄ, true, true, ) } func (ec *executionContext) fieldContext_Edit_comments(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Edit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_EditComment_id(ctx, field) case "user": return ec.fieldContext_EditComment_user(ctx, field) case "date": return ec.fieldContext_EditComment_date(ctx, field) case "comment": return ec.fieldContext_EditComment_comment(ctx, field) case "edit": return ec.fieldContext_EditComment_edit(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type EditComment", field.Name) }, } return fc, nil } func (ec *executionContext) _Edit_votes(ctx context.Context, field graphql.CollectedField, obj *Edit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Edit_votes, func(ctx context.Context) (any, error) { return ec.Resolvers.Edit().Votes(ctx, obj) }, nil, ec.marshalNEditVote2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditVoteᚄ, true, true, ) } func (ec *executionContext) fieldContext_Edit_votes(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Edit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "user": return ec.fieldContext_EditVote_user(ctx, field) case "date": return ec.fieldContext_EditVote_date(ctx, field) case "vote": return ec.fieldContext_EditVote_vote(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type EditVote", field.Name) }, } return fc, nil } func (ec *executionContext) _Edit_vote_count(ctx context.Context, field graphql.CollectedField, obj *Edit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Edit_vote_count, func(ctx context.Context) (any, error) { return obj.VoteCount, nil }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_Edit_vote_count(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Edit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _Edit_destructive(ctx context.Context, field graphql.CollectedField, obj *Edit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Edit_destructive, func(ctx context.Context) (any, error) { return ec.Resolvers.Edit().Destructive(ctx, obj) }, nil, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_Edit_destructive(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Edit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } return fc, nil } func (ec *executionContext) _Edit_status(ctx context.Context, field graphql.CollectedField, obj *Edit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Edit_status, func(ctx context.Context) (any, error) { return ec.Resolvers.Edit().Status(ctx, obj) }, nil, ec.marshalNVoteStatusEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐVoteStatusEnum, true, true, ) } func (ec *executionContext) fieldContext_Edit_status(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Edit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type VoteStatusEnum does not have child fields") }, } return fc, nil } func (ec *executionContext) _Edit_applied(ctx context.Context, field graphql.CollectedField, obj *Edit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Edit_applied, func(ctx context.Context) (any, error) { return obj.Applied, nil }, nil, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_Edit_applied(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Edit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } return fc, nil } func (ec *executionContext) _Edit_update_count(ctx context.Context, field graphql.CollectedField, obj *Edit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Edit_update_count, func(ctx context.Context) (any, error) { return obj.UpdateCount, nil }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_Edit_update_count(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Edit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _Edit_updatable(ctx context.Context, field graphql.CollectedField, obj *Edit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Edit_updatable, func(ctx context.Context) (any, error) { return ec.Resolvers.Edit().Updatable(ctx, obj) }, nil, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_Edit_updatable(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Edit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } return fc, nil } func (ec *executionContext) _Edit_created(ctx context.Context, field graphql.CollectedField, obj *Edit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Edit_created, func(ctx context.Context) (any, error) { return ec.Resolvers.Edit().Created(ctx, obj) }, nil, ec.marshalNTime2ᚖtimeᚐTime, true, true, ) } func (ec *executionContext) fieldContext_Edit_created(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Edit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Time does not have child fields") }, } return fc, nil } func (ec *executionContext) _Edit_updated(ctx context.Context, field graphql.CollectedField, obj *Edit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Edit_updated, func(ctx context.Context) (any, error) { return ec.Resolvers.Edit().Updated(ctx, obj) }, nil, ec.marshalOTime2ᚖtimeᚐTime, true, false, ) } func (ec *executionContext) fieldContext_Edit_updated(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Edit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Time does not have child fields") }, } return fc, nil } func (ec *executionContext) _Edit_closed(ctx context.Context, field graphql.CollectedField, obj *Edit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Edit_closed, func(ctx context.Context) (any, error) { return ec.Resolvers.Edit().Closed(ctx, obj) }, nil, ec.marshalOTime2ᚖtimeᚐTime, true, false, ) } func (ec *executionContext) fieldContext_Edit_closed(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Edit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Time does not have child fields") }, } return fc, nil } func (ec *executionContext) _Edit_expires(ctx context.Context, field graphql.CollectedField, obj *Edit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Edit_expires, func(ctx context.Context) (any, error) { return ec.Resolvers.Edit().Expires(ctx, obj) }, nil, ec.marshalOTime2ᚖtimeᚐTime, true, false, ) } func (ec *executionContext) fieldContext_Edit_expires(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Edit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Time does not have child fields") }, } return fc, nil } func (ec *executionContext) _EditComment_id(ctx context.Context, field graphql.CollectedField, obj *EditComment) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_EditComment_id, func(ctx context.Context) (any, error) { return obj.ID, nil }, nil, ec.marshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID, true, true, ) } func (ec *executionContext) fieldContext_EditComment_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "EditComment", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type ID does not have child fields") }, } return fc, nil } func (ec *executionContext) _EditComment_user(ctx context.Context, field graphql.CollectedField, obj *EditComment) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_EditComment_user, func(ctx context.Context) (any, error) { return ec.Resolvers.EditComment().User(ctx, obj) }, nil, ec.marshalOUser2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUser, true, false, ) } func (ec *executionContext) fieldContext_EditComment_user(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "EditComment", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_User_id(ctx, field) case "name": return ec.fieldContext_User_name(ctx, field) case "roles": return ec.fieldContext_User_roles(ctx, field) case "email": return ec.fieldContext_User_email(ctx, field) case "api_key": return ec.fieldContext_User_api_key(ctx, field) case "notification_subscriptions": return ec.fieldContext_User_notification_subscriptions(ctx, field) case "vote_count": return ec.fieldContext_User_vote_count(ctx, field) case "edit_count": return ec.fieldContext_User_edit_count(ctx, field) case "api_calls": return ec.fieldContext_User_api_calls(ctx, field) case "invited_by": return ec.fieldContext_User_invited_by(ctx, field) case "invite_tokens": return ec.fieldContext_User_invite_tokens(ctx, field) case "active_invite_codes": return ec.fieldContext_User_active_invite_codes(ctx, field) case "invite_codes": return ec.fieldContext_User_invite_codes(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type User", field.Name) }, } return fc, nil } func (ec *executionContext) _EditComment_date(ctx context.Context, field graphql.CollectedField, obj *EditComment) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_EditComment_date, func(ctx context.Context) (any, error) { return ec.Resolvers.EditComment().Date(ctx, obj) }, nil, ec.marshalNTime2ᚖtimeᚐTime, true, true, ) } func (ec *executionContext) fieldContext_EditComment_date(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "EditComment", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Time does not have child fields") }, } return fc, nil } func (ec *executionContext) _EditComment_comment(ctx context.Context, field graphql.CollectedField, obj *EditComment) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_EditComment_comment, func(ctx context.Context) (any, error) { return ec.Resolvers.EditComment().Comment(ctx, obj) }, nil, ec.marshalNString2string, true, true, ) } func (ec *executionContext) fieldContext_EditComment_comment(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "EditComment", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _EditComment_edit(ctx context.Context, field graphql.CollectedField, obj *EditComment) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_EditComment_edit, func(ctx context.Context) (any, error) { return ec.Resolvers.EditComment().Edit(ctx, obj) }, nil, ec.marshalNEdit2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEdit, true, true, ) } func (ec *executionContext) fieldContext_EditComment_edit(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "EditComment", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Edit_id(ctx, field) case "user": return ec.fieldContext_Edit_user(ctx, field) case "target": return ec.fieldContext_Edit_target(ctx, field) case "target_type": return ec.fieldContext_Edit_target_type(ctx, field) case "merge_sources": return ec.fieldContext_Edit_merge_sources(ctx, field) case "operation": return ec.fieldContext_Edit_operation(ctx, field) case "bot": return ec.fieldContext_Edit_bot(ctx, field) case "details": return ec.fieldContext_Edit_details(ctx, field) case "old_details": return ec.fieldContext_Edit_old_details(ctx, field) case "options": return ec.fieldContext_Edit_options(ctx, field) case "comments": return ec.fieldContext_Edit_comments(ctx, field) case "votes": return ec.fieldContext_Edit_votes(ctx, field) case "vote_count": return ec.fieldContext_Edit_vote_count(ctx, field) case "destructive": return ec.fieldContext_Edit_destructive(ctx, field) case "status": return ec.fieldContext_Edit_status(ctx, field) case "applied": return ec.fieldContext_Edit_applied(ctx, field) case "update_count": return ec.fieldContext_Edit_update_count(ctx, field) case "updatable": return ec.fieldContext_Edit_updatable(ctx, field) case "created": return ec.fieldContext_Edit_created(ctx, field) case "updated": return ec.fieldContext_Edit_updated(ctx, field) case "closed": return ec.fieldContext_Edit_closed(ctx, field) case "expires": return ec.fieldContext_Edit_expires(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Edit", field.Name) }, } return fc, nil } func (ec *executionContext) _EditVote_user(ctx context.Context, field graphql.CollectedField, obj *EditVote) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_EditVote_user, func(ctx context.Context) (any, error) { return ec.Resolvers.EditVote().User(ctx, obj) }, nil, ec.marshalOUser2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUser, true, false, ) } func (ec *executionContext) fieldContext_EditVote_user(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "EditVote", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_User_id(ctx, field) case "name": return ec.fieldContext_User_name(ctx, field) case "roles": return ec.fieldContext_User_roles(ctx, field) case "email": return ec.fieldContext_User_email(ctx, field) case "api_key": return ec.fieldContext_User_api_key(ctx, field) case "notification_subscriptions": return ec.fieldContext_User_notification_subscriptions(ctx, field) case "vote_count": return ec.fieldContext_User_vote_count(ctx, field) case "edit_count": return ec.fieldContext_User_edit_count(ctx, field) case "api_calls": return ec.fieldContext_User_api_calls(ctx, field) case "invited_by": return ec.fieldContext_User_invited_by(ctx, field) case "invite_tokens": return ec.fieldContext_User_invite_tokens(ctx, field) case "active_invite_codes": return ec.fieldContext_User_active_invite_codes(ctx, field) case "invite_codes": return ec.fieldContext_User_invite_codes(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type User", field.Name) }, } return fc, nil } func (ec *executionContext) _EditVote_date(ctx context.Context, field graphql.CollectedField, obj *EditVote) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_EditVote_date, func(ctx context.Context) (any, error) { return ec.Resolvers.EditVote().Date(ctx, obj) }, nil, ec.marshalNTime2ᚖtimeᚐTime, true, true, ) } func (ec *executionContext) fieldContext_EditVote_date(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "EditVote", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Time does not have child fields") }, } return fc, nil } func (ec *executionContext) _EditVote_vote(ctx context.Context, field graphql.CollectedField, obj *EditVote) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_EditVote_vote, func(ctx context.Context) (any, error) { return ec.Resolvers.EditVote().Vote(ctx, obj) }, nil, ec.marshalNVoteTypeEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐVoteTypeEnum, true, true, ) } func (ec *executionContext) fieldContext_EditVote_vote(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "EditVote", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type VoteTypeEnum does not have child fields") }, } return fc, nil } func (ec *executionContext) _FailedOwnEdit_edit(ctx context.Context, field graphql.CollectedField, obj *FailedOwnEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_FailedOwnEdit_edit, func(ctx context.Context) (any, error) { return obj.Edit, nil }, nil, ec.marshalNEdit2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEdit, true, true, ) } func (ec *executionContext) fieldContext_FailedOwnEdit_edit(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "FailedOwnEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Edit_id(ctx, field) case "user": return ec.fieldContext_Edit_user(ctx, field) case "target": return ec.fieldContext_Edit_target(ctx, field) case "target_type": return ec.fieldContext_Edit_target_type(ctx, field) case "merge_sources": return ec.fieldContext_Edit_merge_sources(ctx, field) case "operation": return ec.fieldContext_Edit_operation(ctx, field) case "bot": return ec.fieldContext_Edit_bot(ctx, field) case "details": return ec.fieldContext_Edit_details(ctx, field) case "old_details": return ec.fieldContext_Edit_old_details(ctx, field) case "options": return ec.fieldContext_Edit_options(ctx, field) case "comments": return ec.fieldContext_Edit_comments(ctx, field) case "votes": return ec.fieldContext_Edit_votes(ctx, field) case "vote_count": return ec.fieldContext_Edit_vote_count(ctx, field) case "destructive": return ec.fieldContext_Edit_destructive(ctx, field) case "status": return ec.fieldContext_Edit_status(ctx, field) case "applied": return ec.fieldContext_Edit_applied(ctx, field) case "update_count": return ec.fieldContext_Edit_update_count(ctx, field) case "updatable": return ec.fieldContext_Edit_updatable(ctx, field) case "created": return ec.fieldContext_Edit_created(ctx, field) case "updated": return ec.fieldContext_Edit_updated(ctx, field) case "closed": return ec.fieldContext_Edit_closed(ctx, field) case "expires": return ec.fieldContext_Edit_expires(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Edit", field.Name) }, } return fc, nil } func (ec *executionContext) _FavoritePerformerEdit_edit(ctx context.Context, field graphql.CollectedField, obj *FavoritePerformerEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_FavoritePerformerEdit_edit, func(ctx context.Context) (any, error) { return obj.Edit, nil }, nil, ec.marshalNEdit2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEdit, true, true, ) } func (ec *executionContext) fieldContext_FavoritePerformerEdit_edit(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "FavoritePerformerEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Edit_id(ctx, field) case "user": return ec.fieldContext_Edit_user(ctx, field) case "target": return ec.fieldContext_Edit_target(ctx, field) case "target_type": return ec.fieldContext_Edit_target_type(ctx, field) case "merge_sources": return ec.fieldContext_Edit_merge_sources(ctx, field) case "operation": return ec.fieldContext_Edit_operation(ctx, field) case "bot": return ec.fieldContext_Edit_bot(ctx, field) case "details": return ec.fieldContext_Edit_details(ctx, field) case "old_details": return ec.fieldContext_Edit_old_details(ctx, field) case "options": return ec.fieldContext_Edit_options(ctx, field) case "comments": return ec.fieldContext_Edit_comments(ctx, field) case "votes": return ec.fieldContext_Edit_votes(ctx, field) case "vote_count": return ec.fieldContext_Edit_vote_count(ctx, field) case "destructive": return ec.fieldContext_Edit_destructive(ctx, field) case "status": return ec.fieldContext_Edit_status(ctx, field) case "applied": return ec.fieldContext_Edit_applied(ctx, field) case "update_count": return ec.fieldContext_Edit_update_count(ctx, field) case "updatable": return ec.fieldContext_Edit_updatable(ctx, field) case "created": return ec.fieldContext_Edit_created(ctx, field) case "updated": return ec.fieldContext_Edit_updated(ctx, field) case "closed": return ec.fieldContext_Edit_closed(ctx, field) case "expires": return ec.fieldContext_Edit_expires(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Edit", field.Name) }, } return fc, nil } func (ec *executionContext) _FavoritePerformerScene_scene(ctx context.Context, field graphql.CollectedField, obj *FavoritePerformerScene) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_FavoritePerformerScene_scene, func(ctx context.Context) (any, error) { return obj.Scene, nil }, nil, ec.marshalNScene2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐScene, true, true, ) } func (ec *executionContext) fieldContext_FavoritePerformerScene_scene(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "FavoritePerformerScene", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Scene_id(ctx, field) case "title": return ec.fieldContext_Scene_title(ctx, field) case "details": return ec.fieldContext_Scene_details(ctx, field) case "date": return ec.fieldContext_Scene_date(ctx, field) case "release_date": return ec.fieldContext_Scene_release_date(ctx, field) case "production_date": return ec.fieldContext_Scene_production_date(ctx, field) case "urls": return ec.fieldContext_Scene_urls(ctx, field) case "studio": return ec.fieldContext_Scene_studio(ctx, field) case "tags": return ec.fieldContext_Scene_tags(ctx, field) case "images": return ec.fieldContext_Scene_images(ctx, field) case "performers": return ec.fieldContext_Scene_performers(ctx, field) case "fingerprints": return ec.fieldContext_Scene_fingerprints(ctx, field) case "duration": return ec.fieldContext_Scene_duration(ctx, field) case "director": return ec.fieldContext_Scene_director(ctx, field) case "code": return ec.fieldContext_Scene_code(ctx, field) case "deleted": return ec.fieldContext_Scene_deleted(ctx, field) case "edits": return ec.fieldContext_Scene_edits(ctx, field) case "created": return ec.fieldContext_Scene_created(ctx, field) case "updated": return ec.fieldContext_Scene_updated(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Scene", field.Name) }, } return fc, nil } func (ec *executionContext) _FavoriteStudioEdit_edit(ctx context.Context, field graphql.CollectedField, obj *FavoriteStudioEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_FavoriteStudioEdit_edit, func(ctx context.Context) (any, error) { return obj.Edit, nil }, nil, ec.marshalNEdit2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEdit, true, true, ) } func (ec *executionContext) fieldContext_FavoriteStudioEdit_edit(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "FavoriteStudioEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Edit_id(ctx, field) case "user": return ec.fieldContext_Edit_user(ctx, field) case "target": return ec.fieldContext_Edit_target(ctx, field) case "target_type": return ec.fieldContext_Edit_target_type(ctx, field) case "merge_sources": return ec.fieldContext_Edit_merge_sources(ctx, field) case "operation": return ec.fieldContext_Edit_operation(ctx, field) case "bot": return ec.fieldContext_Edit_bot(ctx, field) case "details": return ec.fieldContext_Edit_details(ctx, field) case "old_details": return ec.fieldContext_Edit_old_details(ctx, field) case "options": return ec.fieldContext_Edit_options(ctx, field) case "comments": return ec.fieldContext_Edit_comments(ctx, field) case "votes": return ec.fieldContext_Edit_votes(ctx, field) case "vote_count": return ec.fieldContext_Edit_vote_count(ctx, field) case "destructive": return ec.fieldContext_Edit_destructive(ctx, field) case "status": return ec.fieldContext_Edit_status(ctx, field) case "applied": return ec.fieldContext_Edit_applied(ctx, field) case "update_count": return ec.fieldContext_Edit_update_count(ctx, field) case "updatable": return ec.fieldContext_Edit_updatable(ctx, field) case "created": return ec.fieldContext_Edit_created(ctx, field) case "updated": return ec.fieldContext_Edit_updated(ctx, field) case "closed": return ec.fieldContext_Edit_closed(ctx, field) case "expires": return ec.fieldContext_Edit_expires(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Edit", field.Name) }, } return fc, nil } func (ec *executionContext) _FavoriteStudioScene_scene(ctx context.Context, field graphql.CollectedField, obj *FavoriteStudioScene) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_FavoriteStudioScene_scene, func(ctx context.Context) (any, error) { return obj.Scene, nil }, nil, ec.marshalNScene2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐScene, true, true, ) } func (ec *executionContext) fieldContext_FavoriteStudioScene_scene(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "FavoriteStudioScene", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Scene_id(ctx, field) case "title": return ec.fieldContext_Scene_title(ctx, field) case "details": return ec.fieldContext_Scene_details(ctx, field) case "date": return ec.fieldContext_Scene_date(ctx, field) case "release_date": return ec.fieldContext_Scene_release_date(ctx, field) case "production_date": return ec.fieldContext_Scene_production_date(ctx, field) case "urls": return ec.fieldContext_Scene_urls(ctx, field) case "studio": return ec.fieldContext_Scene_studio(ctx, field) case "tags": return ec.fieldContext_Scene_tags(ctx, field) case "images": return ec.fieldContext_Scene_images(ctx, field) case "performers": return ec.fieldContext_Scene_performers(ctx, field) case "fingerprints": return ec.fieldContext_Scene_fingerprints(ctx, field) case "duration": return ec.fieldContext_Scene_duration(ctx, field) case "director": return ec.fieldContext_Scene_director(ctx, field) case "code": return ec.fieldContext_Scene_code(ctx, field) case "deleted": return ec.fieldContext_Scene_deleted(ctx, field) case "edits": return ec.fieldContext_Scene_edits(ctx, field) case "created": return ec.fieldContext_Scene_created(ctx, field) case "updated": return ec.fieldContext_Scene_updated(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Scene", field.Name) }, } return fc, nil } func (ec *executionContext) _Fingerprint_hash(ctx context.Context, field graphql.CollectedField, obj *Fingerprint) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Fingerprint_hash, func(ctx context.Context) (any, error) { return obj.Hash, nil }, nil, ec.marshalNFingerprintHash2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintHash, true, true, ) } func (ec *executionContext) fieldContext_Fingerprint_hash(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Fingerprint", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type FingerprintHash does not have child fields") }, } return fc, nil } func (ec *executionContext) _Fingerprint_algorithm(ctx context.Context, field graphql.CollectedField, obj *Fingerprint) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Fingerprint_algorithm, func(ctx context.Context) (any, error) { return obj.Algorithm, nil }, nil, ec.marshalNFingerprintAlgorithm2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintAlgorithm, true, true, ) } func (ec *executionContext) fieldContext_Fingerprint_algorithm(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Fingerprint", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type FingerprintAlgorithm does not have child fields") }, } return fc, nil } func (ec *executionContext) _Fingerprint_duration(ctx context.Context, field graphql.CollectedField, obj *Fingerprint) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Fingerprint_duration, func(ctx context.Context) (any, error) { return obj.Duration, nil }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_Fingerprint_duration(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Fingerprint", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _Fingerprint_submissions(ctx context.Context, field graphql.CollectedField, obj *Fingerprint) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Fingerprint_submissions, func(ctx context.Context) (any, error) { return obj.Submissions, nil }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_Fingerprint_submissions(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Fingerprint", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _Fingerprint_reports(ctx context.Context, field graphql.CollectedField, obj *Fingerprint) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Fingerprint_reports, func(ctx context.Context) (any, error) { return obj.Reports, nil }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_Fingerprint_reports(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Fingerprint", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _Fingerprint_created(ctx context.Context, field graphql.CollectedField, obj *Fingerprint) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Fingerprint_created, func(ctx context.Context) (any, error) { return obj.Created, nil }, nil, ec.marshalNTime2timeᚐTime, true, true, ) } func (ec *executionContext) fieldContext_Fingerprint_created(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Fingerprint", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Time does not have child fields") }, } return fc, nil } func (ec *executionContext) _Fingerprint_updated(ctx context.Context, field graphql.CollectedField, obj *Fingerprint) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Fingerprint_updated, func(ctx context.Context) (any, error) { return obj.Updated, nil }, nil, ec.marshalNTime2timeᚐTime, true, true, ) } func (ec *executionContext) fieldContext_Fingerprint_updated(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Fingerprint", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Time does not have child fields") }, } return fc, nil } func (ec *executionContext) _Fingerprint_user_submitted(ctx context.Context, field graphql.CollectedField, obj *Fingerprint) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Fingerprint_user_submitted, func(ctx context.Context) (any, error) { return obj.UserSubmitted, nil }, nil, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_Fingerprint_user_submitted(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Fingerprint", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } return fc, nil } func (ec *executionContext) _Fingerprint_user_reported(ctx context.Context, field graphql.CollectedField, obj *Fingerprint) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Fingerprint_user_reported, func(ctx context.Context) (any, error) { return obj.UserReported, nil }, nil, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_Fingerprint_user_reported(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Fingerprint", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } return fc, nil } func (ec *executionContext) _FingerprintSubmissionResult_hash(ctx context.Context, field graphql.CollectedField, obj *FingerprintSubmissionResult) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_FingerprintSubmissionResult_hash, func(ctx context.Context) (any, error) { return obj.Hash, nil }, nil, ec.marshalNFingerprintHash2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintHash, true, true, ) } func (ec *executionContext) fieldContext_FingerprintSubmissionResult_hash(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "FingerprintSubmissionResult", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type FingerprintHash does not have child fields") }, } return fc, nil } func (ec *executionContext) _FingerprintSubmissionResult_scene_id(ctx context.Context, field graphql.CollectedField, obj *FingerprintSubmissionResult) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_FingerprintSubmissionResult_scene_id, func(ctx context.Context) (any, error) { return obj.SceneID, nil }, nil, ec.marshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID, true, true, ) } func (ec *executionContext) fieldContext_FingerprintSubmissionResult_scene_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "FingerprintSubmissionResult", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type ID does not have child fields") }, } return fc, nil } func (ec *executionContext) _FingerprintSubmissionResult_error(ctx context.Context, field graphql.CollectedField, obj *FingerprintSubmissionResult) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_FingerprintSubmissionResult_error, func(ctx context.Context) (any, error) { return obj.Error, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_FingerprintSubmissionResult_error(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "FingerprintSubmissionResult", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _FingerprintedSceneEdit_edit(ctx context.Context, field graphql.CollectedField, obj *FingerprintedSceneEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_FingerprintedSceneEdit_edit, func(ctx context.Context) (any, error) { return obj.Edit, nil }, nil, ec.marshalNEdit2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEdit, true, true, ) } func (ec *executionContext) fieldContext_FingerprintedSceneEdit_edit(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "FingerprintedSceneEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Edit_id(ctx, field) case "user": return ec.fieldContext_Edit_user(ctx, field) case "target": return ec.fieldContext_Edit_target(ctx, field) case "target_type": return ec.fieldContext_Edit_target_type(ctx, field) case "merge_sources": return ec.fieldContext_Edit_merge_sources(ctx, field) case "operation": return ec.fieldContext_Edit_operation(ctx, field) case "bot": return ec.fieldContext_Edit_bot(ctx, field) case "details": return ec.fieldContext_Edit_details(ctx, field) case "old_details": return ec.fieldContext_Edit_old_details(ctx, field) case "options": return ec.fieldContext_Edit_options(ctx, field) case "comments": return ec.fieldContext_Edit_comments(ctx, field) case "votes": return ec.fieldContext_Edit_votes(ctx, field) case "vote_count": return ec.fieldContext_Edit_vote_count(ctx, field) case "destructive": return ec.fieldContext_Edit_destructive(ctx, field) case "status": return ec.fieldContext_Edit_status(ctx, field) case "applied": return ec.fieldContext_Edit_applied(ctx, field) case "update_count": return ec.fieldContext_Edit_update_count(ctx, field) case "updatable": return ec.fieldContext_Edit_updatable(ctx, field) case "created": return ec.fieldContext_Edit_created(ctx, field) case "updated": return ec.fieldContext_Edit_updated(ctx, field) case "closed": return ec.fieldContext_Edit_closed(ctx, field) case "expires": return ec.fieldContext_Edit_expires(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Edit", field.Name) }, } return fc, nil } func (ec *executionContext) _FuzzyDate_date(ctx context.Context, field graphql.CollectedField, obj *FuzzyDate) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_FuzzyDate_date, func(ctx context.Context) (any, error) { return obj.Date, nil }, nil, ec.marshalNDate2string, true, true, ) } func (ec *executionContext) fieldContext_FuzzyDate_date(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "FuzzyDate", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Date does not have child fields") }, } return fc, nil } func (ec *executionContext) _FuzzyDate_accuracy(ctx context.Context, field graphql.CollectedField, obj *FuzzyDate) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_FuzzyDate_accuracy, func(ctx context.Context) (any, error) { return obj.Accuracy, nil }, nil, ec.marshalNDateAccuracyEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDateAccuracyEnum, true, true, ) } func (ec *executionContext) fieldContext_FuzzyDate_accuracy(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "FuzzyDate", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type DateAccuracyEnum does not have child fields") }, } return fc, nil } func (ec *executionContext) _GenderFacet_gender(ctx context.Context, field graphql.CollectedField, obj *GenderFacet) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_GenderFacet_gender, func(ctx context.Context) (any, error) { return obj.Gender, nil }, nil, ec.marshalNGenderEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐGenderEnum, true, true, ) } func (ec *executionContext) fieldContext_GenderFacet_gender(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "GenderFacet", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type GenderEnum does not have child fields") }, } return fc, nil } func (ec *executionContext) _GenderFacet_count(ctx context.Context, field graphql.CollectedField, obj *GenderFacet) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_GenderFacet_count, func(ctx context.Context) (any, error) { return obj.Count, nil }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_GenderFacet_count(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "GenderFacet", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _Image_id(ctx context.Context, field graphql.CollectedField, obj *Image) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Image_id, func(ctx context.Context) (any, error) { return obj.ID, nil }, nil, ec.marshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID, true, true, ) } func (ec *executionContext) fieldContext_Image_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Image", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type ID does not have child fields") }, } return fc, nil } func (ec *executionContext) _Image_url(ctx context.Context, field graphql.CollectedField, obj *Image) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Image_url, func(ctx context.Context) (any, error) { return ec.Resolvers.Image().URL(ctx, obj) }, nil, ec.marshalNString2string, true, true, ) } func (ec *executionContext) fieldContext_Image_url(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Image", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _Image_width(ctx context.Context, field graphql.CollectedField, obj *Image) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Image_width, func(ctx context.Context) (any, error) { return obj.Width, nil }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_Image_width(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Image", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _Image_height(ctx context.Context, field graphql.CollectedField, obj *Image) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Image_height, func(ctx context.Context) (any, error) { return obj.Height, nil }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_Image_height(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Image", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _InviteKey_id(ctx context.Context, field graphql.CollectedField, obj *InviteKey) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_InviteKey_id, func(ctx context.Context) (any, error) { return obj.ID, nil }, nil, ec.marshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID, true, true, ) } func (ec *executionContext) fieldContext_InviteKey_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "InviteKey", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type ID does not have child fields") }, } return fc, nil } func (ec *executionContext) _InviteKey_uses(ctx context.Context, field graphql.CollectedField, obj *InviteKey) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_InviteKey_uses, func(ctx context.Context) (any, error) { return obj.Uses, nil }, nil, ec.marshalOInt2ᚖint, true, false, ) } func (ec *executionContext) fieldContext_InviteKey_uses(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "InviteKey", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _InviteKey_expires(ctx context.Context, field graphql.CollectedField, obj *InviteKey) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_InviteKey_expires, func(ctx context.Context) (any, error) { return obj.Expires, nil }, nil, ec.marshalOTime2ᚖtimeᚐTime, true, false, ) } func (ec *executionContext) fieldContext_InviteKey_expires(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "InviteKey", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Time does not have child fields") }, } return fc, nil } func (ec *executionContext) _Measurements_cup_size(ctx context.Context, field graphql.CollectedField, obj *Measurements) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Measurements_cup_size, func(ctx context.Context) (any, error) { return obj.CupSize, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_Measurements_cup_size(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Measurements", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _Measurements_band_size(ctx context.Context, field graphql.CollectedField, obj *Measurements) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Measurements_band_size, func(ctx context.Context) (any, error) { return obj.BandSize, nil }, nil, ec.marshalOInt2ᚖint, true, false, ) } func (ec *executionContext) fieldContext_Measurements_band_size(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Measurements", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _Measurements_waist(ctx context.Context, field graphql.CollectedField, obj *Measurements) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Measurements_waist, func(ctx context.Context) (any, error) { return obj.Waist, nil }, nil, ec.marshalOInt2ᚖint, true, false, ) } func (ec *executionContext) fieldContext_Measurements_waist(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Measurements", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _Measurements_hip(ctx context.Context, field graphql.CollectedField, obj *Measurements) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Measurements_hip, func(ctx context.Context) (any, error) { return obj.Hip, nil }, nil, ec.marshalOInt2ᚖint, true, false, ) } func (ec *executionContext) fieldContext_Measurements_hip(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Measurements", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _ModAudit_id(ctx context.Context, field graphql.CollectedField, obj *ModAudit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_ModAudit_id, func(ctx context.Context) (any, error) { return obj.ID, nil }, nil, ec.marshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID, true, true, ) } func (ec *executionContext) fieldContext_ModAudit_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "ModAudit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type ID does not have child fields") }, } return fc, nil } func (ec *executionContext) _ModAudit_action(ctx context.Context, field graphql.CollectedField, obj *ModAudit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_ModAudit_action, func(ctx context.Context) (any, error) { return ec.Resolvers.ModAudit().Action(ctx, obj) }, nil, ec.marshalNModAuditActionEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐModAuditActionEnum, true, true, ) } func (ec *executionContext) fieldContext_ModAudit_action(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "ModAudit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type ModAuditActionEnum does not have child fields") }, } return fc, nil } func (ec *executionContext) _ModAudit_user(ctx context.Context, field graphql.CollectedField, obj *ModAudit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_ModAudit_user, func(ctx context.Context) (any, error) { return ec.Resolvers.ModAudit().User(ctx, obj) }, nil, ec.marshalOUser2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUser, true, false, ) } func (ec *executionContext) fieldContext_ModAudit_user(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "ModAudit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_User_id(ctx, field) case "name": return ec.fieldContext_User_name(ctx, field) case "roles": return ec.fieldContext_User_roles(ctx, field) case "email": return ec.fieldContext_User_email(ctx, field) case "api_key": return ec.fieldContext_User_api_key(ctx, field) case "notification_subscriptions": return ec.fieldContext_User_notification_subscriptions(ctx, field) case "vote_count": return ec.fieldContext_User_vote_count(ctx, field) case "edit_count": return ec.fieldContext_User_edit_count(ctx, field) case "api_calls": return ec.fieldContext_User_api_calls(ctx, field) case "invited_by": return ec.fieldContext_User_invited_by(ctx, field) case "invite_tokens": return ec.fieldContext_User_invite_tokens(ctx, field) case "active_invite_codes": return ec.fieldContext_User_active_invite_codes(ctx, field) case "invite_codes": return ec.fieldContext_User_invite_codes(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type User", field.Name) }, } return fc, nil } func (ec *executionContext) _ModAudit_target_id(ctx context.Context, field graphql.CollectedField, obj *ModAudit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_ModAudit_target_id, func(ctx context.Context) (any, error) { return obj.TargetID, nil }, nil, ec.marshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID, true, true, ) } func (ec *executionContext) fieldContext_ModAudit_target_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "ModAudit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type ID does not have child fields") }, } return fc, nil } func (ec *executionContext) _ModAudit_target_type(ctx context.Context, field graphql.CollectedField, obj *ModAudit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_ModAudit_target_type, func(ctx context.Context) (any, error) { return obj.TargetType, nil }, nil, ec.marshalNString2string, true, true, ) } func (ec *executionContext) fieldContext_ModAudit_target_type(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "ModAudit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _ModAudit_data(ctx context.Context, field graphql.CollectedField, obj *ModAudit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_ModAudit_data, func(ctx context.Context) (any, error) { return obj.Data, nil }, nil, ec.marshalNString2string, true, true, ) } func (ec *executionContext) fieldContext_ModAudit_data(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "ModAudit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _ModAudit_reason(ctx context.Context, field graphql.CollectedField, obj *ModAudit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_ModAudit_reason, func(ctx context.Context) (any, error) { return obj.Reason, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_ModAudit_reason(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "ModAudit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _ModAudit_created_at(ctx context.Context, field graphql.CollectedField, obj *ModAudit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_ModAudit_created_at, func(ctx context.Context) (any, error) { return obj.CreatedAt, nil }, nil, ec.marshalNTime2timeᚐTime, true, true, ) } func (ec *executionContext) fieldContext_ModAudit_created_at(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "ModAudit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Time does not have child fields") }, } return fc, nil } func (ec *executionContext) _Mutation_sceneCreate(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_sceneCreate, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().SceneCreate(ctx, fc.Args["input"].(SceneCreateInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "MODIFY") if err != nil { var zeroVal *Scene return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *Scene return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalOScene2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐScene, true, false, ) } func (ec *executionContext) fieldContext_Mutation_sceneCreate(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Scene_id(ctx, field) case "title": return ec.fieldContext_Scene_title(ctx, field) case "details": return ec.fieldContext_Scene_details(ctx, field) case "date": return ec.fieldContext_Scene_date(ctx, field) case "release_date": return ec.fieldContext_Scene_release_date(ctx, field) case "production_date": return ec.fieldContext_Scene_production_date(ctx, field) case "urls": return ec.fieldContext_Scene_urls(ctx, field) case "studio": return ec.fieldContext_Scene_studio(ctx, field) case "tags": return ec.fieldContext_Scene_tags(ctx, field) case "images": return ec.fieldContext_Scene_images(ctx, field) case "performers": return ec.fieldContext_Scene_performers(ctx, field) case "fingerprints": return ec.fieldContext_Scene_fingerprints(ctx, field) case "duration": return ec.fieldContext_Scene_duration(ctx, field) case "director": return ec.fieldContext_Scene_director(ctx, field) case "code": return ec.fieldContext_Scene_code(ctx, field) case "deleted": return ec.fieldContext_Scene_deleted(ctx, field) case "edits": return ec.fieldContext_Scene_edits(ctx, field) case "created": return ec.fieldContext_Scene_created(ctx, field) case "updated": return ec.fieldContext_Scene_updated(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Scene", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_sceneCreate_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_sceneUpdate(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_sceneUpdate, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().SceneUpdate(ctx, fc.Args["input"].(SceneUpdateInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "MODIFY") if err != nil { var zeroVal *Scene return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *Scene return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalOScene2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐScene, true, false, ) } func (ec *executionContext) fieldContext_Mutation_sceneUpdate(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Scene_id(ctx, field) case "title": return ec.fieldContext_Scene_title(ctx, field) case "details": return ec.fieldContext_Scene_details(ctx, field) case "date": return ec.fieldContext_Scene_date(ctx, field) case "release_date": return ec.fieldContext_Scene_release_date(ctx, field) case "production_date": return ec.fieldContext_Scene_production_date(ctx, field) case "urls": return ec.fieldContext_Scene_urls(ctx, field) case "studio": return ec.fieldContext_Scene_studio(ctx, field) case "tags": return ec.fieldContext_Scene_tags(ctx, field) case "images": return ec.fieldContext_Scene_images(ctx, field) case "performers": return ec.fieldContext_Scene_performers(ctx, field) case "fingerprints": return ec.fieldContext_Scene_fingerprints(ctx, field) case "duration": return ec.fieldContext_Scene_duration(ctx, field) case "director": return ec.fieldContext_Scene_director(ctx, field) case "code": return ec.fieldContext_Scene_code(ctx, field) case "deleted": return ec.fieldContext_Scene_deleted(ctx, field) case "edits": return ec.fieldContext_Scene_edits(ctx, field) case "created": return ec.fieldContext_Scene_created(ctx, field) case "updated": return ec.fieldContext_Scene_updated(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Scene", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_sceneUpdate_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_sceneDestroy(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_sceneDestroy, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().SceneDestroy(ctx, fc.Args["input"].(SceneDestroyInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "MODIFY") if err != nil { var zeroVal bool return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal bool return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_Mutation_sceneDestroy(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_sceneDestroy_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_performerCreate(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_performerCreate, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().PerformerCreate(ctx, fc.Args["input"].(PerformerCreateInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "MODIFY") if err != nil { var zeroVal *Performer return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *Performer return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalOPerformer2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformer, true, false, ) } func (ec *executionContext) fieldContext_Mutation_performerCreate(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Performer_id(ctx, field) case "name": return ec.fieldContext_Performer_name(ctx, field) case "disambiguation": return ec.fieldContext_Performer_disambiguation(ctx, field) case "aliases": return ec.fieldContext_Performer_aliases(ctx, field) case "gender": return ec.fieldContext_Performer_gender(ctx, field) case "urls": return ec.fieldContext_Performer_urls(ctx, field) case "birthdate": return ec.fieldContext_Performer_birthdate(ctx, field) case "birth_date": return ec.fieldContext_Performer_birth_date(ctx, field) case "death_date": return ec.fieldContext_Performer_death_date(ctx, field) case "age": return ec.fieldContext_Performer_age(ctx, field) case "ethnicity": return ec.fieldContext_Performer_ethnicity(ctx, field) case "country": return ec.fieldContext_Performer_country(ctx, field) case "eye_color": return ec.fieldContext_Performer_eye_color(ctx, field) case "hair_color": return ec.fieldContext_Performer_hair_color(ctx, field) case "height": return ec.fieldContext_Performer_height(ctx, field) case "measurements": return ec.fieldContext_Performer_measurements(ctx, field) case "cup_size": return ec.fieldContext_Performer_cup_size(ctx, field) case "band_size": return ec.fieldContext_Performer_band_size(ctx, field) case "waist_size": return ec.fieldContext_Performer_waist_size(ctx, field) case "hip_size": return ec.fieldContext_Performer_hip_size(ctx, field) case "breast_type": return ec.fieldContext_Performer_breast_type(ctx, field) case "career_start_year": return ec.fieldContext_Performer_career_start_year(ctx, field) case "career_end_year": return ec.fieldContext_Performer_career_end_year(ctx, field) case "tattoos": return ec.fieldContext_Performer_tattoos(ctx, field) case "piercings": return ec.fieldContext_Performer_piercings(ctx, field) case "images": return ec.fieldContext_Performer_images(ctx, field) case "deleted": return ec.fieldContext_Performer_deleted(ctx, field) case "edits": return ec.fieldContext_Performer_edits(ctx, field) case "scene_count": return ec.fieldContext_Performer_scene_count(ctx, field) case "scenes": return ec.fieldContext_Performer_scenes(ctx, field) case "merged_ids": return ec.fieldContext_Performer_merged_ids(ctx, field) case "merged_into_id": return ec.fieldContext_Performer_merged_into_id(ctx, field) case "studios": return ec.fieldContext_Performer_studios(ctx, field) case "is_favorite": return ec.fieldContext_Performer_is_favorite(ctx, field) case "created": return ec.fieldContext_Performer_created(ctx, field) case "updated": return ec.fieldContext_Performer_updated(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Performer", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_performerCreate_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_performerUpdate(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_performerUpdate, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().PerformerUpdate(ctx, fc.Args["input"].(PerformerUpdateInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "MODIFY") if err != nil { var zeroVal *Performer return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *Performer return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalOPerformer2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformer, true, false, ) } func (ec *executionContext) fieldContext_Mutation_performerUpdate(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Performer_id(ctx, field) case "name": return ec.fieldContext_Performer_name(ctx, field) case "disambiguation": return ec.fieldContext_Performer_disambiguation(ctx, field) case "aliases": return ec.fieldContext_Performer_aliases(ctx, field) case "gender": return ec.fieldContext_Performer_gender(ctx, field) case "urls": return ec.fieldContext_Performer_urls(ctx, field) case "birthdate": return ec.fieldContext_Performer_birthdate(ctx, field) case "birth_date": return ec.fieldContext_Performer_birth_date(ctx, field) case "death_date": return ec.fieldContext_Performer_death_date(ctx, field) case "age": return ec.fieldContext_Performer_age(ctx, field) case "ethnicity": return ec.fieldContext_Performer_ethnicity(ctx, field) case "country": return ec.fieldContext_Performer_country(ctx, field) case "eye_color": return ec.fieldContext_Performer_eye_color(ctx, field) case "hair_color": return ec.fieldContext_Performer_hair_color(ctx, field) case "height": return ec.fieldContext_Performer_height(ctx, field) case "measurements": return ec.fieldContext_Performer_measurements(ctx, field) case "cup_size": return ec.fieldContext_Performer_cup_size(ctx, field) case "band_size": return ec.fieldContext_Performer_band_size(ctx, field) case "waist_size": return ec.fieldContext_Performer_waist_size(ctx, field) case "hip_size": return ec.fieldContext_Performer_hip_size(ctx, field) case "breast_type": return ec.fieldContext_Performer_breast_type(ctx, field) case "career_start_year": return ec.fieldContext_Performer_career_start_year(ctx, field) case "career_end_year": return ec.fieldContext_Performer_career_end_year(ctx, field) case "tattoos": return ec.fieldContext_Performer_tattoos(ctx, field) case "piercings": return ec.fieldContext_Performer_piercings(ctx, field) case "images": return ec.fieldContext_Performer_images(ctx, field) case "deleted": return ec.fieldContext_Performer_deleted(ctx, field) case "edits": return ec.fieldContext_Performer_edits(ctx, field) case "scene_count": return ec.fieldContext_Performer_scene_count(ctx, field) case "scenes": return ec.fieldContext_Performer_scenes(ctx, field) case "merged_ids": return ec.fieldContext_Performer_merged_ids(ctx, field) case "merged_into_id": return ec.fieldContext_Performer_merged_into_id(ctx, field) case "studios": return ec.fieldContext_Performer_studios(ctx, field) case "is_favorite": return ec.fieldContext_Performer_is_favorite(ctx, field) case "created": return ec.fieldContext_Performer_created(ctx, field) case "updated": return ec.fieldContext_Performer_updated(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Performer", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_performerUpdate_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_performerDestroy(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_performerDestroy, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().PerformerDestroy(ctx, fc.Args["input"].(PerformerDestroyInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "MODIFY") if err != nil { var zeroVal bool return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal bool return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_Mutation_performerDestroy(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_performerDestroy_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_studioCreate(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_studioCreate, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().StudioCreate(ctx, fc.Args["input"].(StudioCreateInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "MODIFY") if err != nil { var zeroVal *Studio return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *Studio return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalOStudio2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStudio, true, false, ) } func (ec *executionContext) fieldContext_Mutation_studioCreate(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Studio_id(ctx, field) case "name": return ec.fieldContext_Studio_name(ctx, field) case "aliases": return ec.fieldContext_Studio_aliases(ctx, field) case "urls": return ec.fieldContext_Studio_urls(ctx, field) case "parent": return ec.fieldContext_Studio_parent(ctx, field) case "child_studios": return ec.fieldContext_Studio_child_studios(ctx, field) case "sub_studios": return ec.fieldContext_Studio_sub_studios(ctx, field) case "images": return ec.fieldContext_Studio_images(ctx, field) case "deleted": return ec.fieldContext_Studio_deleted(ctx, field) case "is_favorite": return ec.fieldContext_Studio_is_favorite(ctx, field) case "created": return ec.fieldContext_Studio_created(ctx, field) case "updated": return ec.fieldContext_Studio_updated(ctx, field) case "performers": return ec.fieldContext_Studio_performers(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Studio", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_studioCreate_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_studioUpdate(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_studioUpdate, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().StudioUpdate(ctx, fc.Args["input"].(StudioUpdateInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "MODIFY") if err != nil { var zeroVal *Studio return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *Studio return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalOStudio2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStudio, true, false, ) } func (ec *executionContext) fieldContext_Mutation_studioUpdate(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Studio_id(ctx, field) case "name": return ec.fieldContext_Studio_name(ctx, field) case "aliases": return ec.fieldContext_Studio_aliases(ctx, field) case "urls": return ec.fieldContext_Studio_urls(ctx, field) case "parent": return ec.fieldContext_Studio_parent(ctx, field) case "child_studios": return ec.fieldContext_Studio_child_studios(ctx, field) case "sub_studios": return ec.fieldContext_Studio_sub_studios(ctx, field) case "images": return ec.fieldContext_Studio_images(ctx, field) case "deleted": return ec.fieldContext_Studio_deleted(ctx, field) case "is_favorite": return ec.fieldContext_Studio_is_favorite(ctx, field) case "created": return ec.fieldContext_Studio_created(ctx, field) case "updated": return ec.fieldContext_Studio_updated(ctx, field) case "performers": return ec.fieldContext_Studio_performers(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Studio", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_studioUpdate_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_studioDestroy(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_studioDestroy, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().StudioDestroy(ctx, fc.Args["input"].(StudioDestroyInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "MODIFY") if err != nil { var zeroVal bool return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal bool return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_Mutation_studioDestroy(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_studioDestroy_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_tagCreate(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_tagCreate, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().TagCreate(ctx, fc.Args["input"].(TagCreateInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "MODIFY") if err != nil { var zeroVal *Tag return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *Tag return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalOTag2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTag, true, false, ) } func (ec *executionContext) fieldContext_Mutation_tagCreate(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Tag_id(ctx, field) case "name": return ec.fieldContext_Tag_name(ctx, field) case "description": return ec.fieldContext_Tag_description(ctx, field) case "aliases": return ec.fieldContext_Tag_aliases(ctx, field) case "deleted": return ec.fieldContext_Tag_deleted(ctx, field) case "edits": return ec.fieldContext_Tag_edits(ctx, field) case "category": return ec.fieldContext_Tag_category(ctx, field) case "created": return ec.fieldContext_Tag_created(ctx, field) case "updated": return ec.fieldContext_Tag_updated(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Tag", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_tagCreate_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_tagUpdate(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_tagUpdate, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().TagUpdate(ctx, fc.Args["input"].(TagUpdateInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "MODIFY") if err != nil { var zeroVal *Tag return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *Tag return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalOTag2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTag, true, false, ) } func (ec *executionContext) fieldContext_Mutation_tagUpdate(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Tag_id(ctx, field) case "name": return ec.fieldContext_Tag_name(ctx, field) case "description": return ec.fieldContext_Tag_description(ctx, field) case "aliases": return ec.fieldContext_Tag_aliases(ctx, field) case "deleted": return ec.fieldContext_Tag_deleted(ctx, field) case "edits": return ec.fieldContext_Tag_edits(ctx, field) case "category": return ec.fieldContext_Tag_category(ctx, field) case "created": return ec.fieldContext_Tag_created(ctx, field) case "updated": return ec.fieldContext_Tag_updated(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Tag", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_tagUpdate_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_tagDestroy(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_tagDestroy, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().TagDestroy(ctx, fc.Args["input"].(TagDestroyInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "MODIFY") if err != nil { var zeroVal bool return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal bool return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_Mutation_tagDestroy(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_tagDestroy_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_userCreate(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_userCreate, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().UserCreate(ctx, fc.Args["input"].(UserCreateInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "ADMIN") if err != nil { var zeroVal *User return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *User return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalOUser2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUser, true, false, ) } func (ec *executionContext) fieldContext_Mutation_userCreate(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_User_id(ctx, field) case "name": return ec.fieldContext_User_name(ctx, field) case "roles": return ec.fieldContext_User_roles(ctx, field) case "email": return ec.fieldContext_User_email(ctx, field) case "api_key": return ec.fieldContext_User_api_key(ctx, field) case "notification_subscriptions": return ec.fieldContext_User_notification_subscriptions(ctx, field) case "vote_count": return ec.fieldContext_User_vote_count(ctx, field) case "edit_count": return ec.fieldContext_User_edit_count(ctx, field) case "api_calls": return ec.fieldContext_User_api_calls(ctx, field) case "invited_by": return ec.fieldContext_User_invited_by(ctx, field) case "invite_tokens": return ec.fieldContext_User_invite_tokens(ctx, field) case "active_invite_codes": return ec.fieldContext_User_active_invite_codes(ctx, field) case "invite_codes": return ec.fieldContext_User_invite_codes(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type User", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_userCreate_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_userUpdate(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_userUpdate, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().UserUpdate(ctx, fc.Args["input"].(UserUpdateInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "ADMIN") if err != nil { var zeroVal *User return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *User return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalOUser2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUser, true, false, ) } func (ec *executionContext) fieldContext_Mutation_userUpdate(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_User_id(ctx, field) case "name": return ec.fieldContext_User_name(ctx, field) case "roles": return ec.fieldContext_User_roles(ctx, field) case "email": return ec.fieldContext_User_email(ctx, field) case "api_key": return ec.fieldContext_User_api_key(ctx, field) case "notification_subscriptions": return ec.fieldContext_User_notification_subscriptions(ctx, field) case "vote_count": return ec.fieldContext_User_vote_count(ctx, field) case "edit_count": return ec.fieldContext_User_edit_count(ctx, field) case "api_calls": return ec.fieldContext_User_api_calls(ctx, field) case "invited_by": return ec.fieldContext_User_invited_by(ctx, field) case "invite_tokens": return ec.fieldContext_User_invite_tokens(ctx, field) case "active_invite_codes": return ec.fieldContext_User_active_invite_codes(ctx, field) case "invite_codes": return ec.fieldContext_User_invite_codes(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type User", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_userUpdate_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_userDestroy(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_userDestroy, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().UserDestroy(ctx, fc.Args["input"].(UserDestroyInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "ADMIN") if err != nil { var zeroVal bool return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal bool return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_Mutation_userDestroy(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_userDestroy_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_imageCreate(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_imageCreate, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().ImageCreate(ctx, fc.Args["input"].(ImageCreateInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "EDIT") if err != nil { var zeroVal *Image return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *Image return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalOImage2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐImage, true, false, ) } func (ec *executionContext) fieldContext_Mutation_imageCreate(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Image_id(ctx, field) case "url": return ec.fieldContext_Image_url(ctx, field) case "width": return ec.fieldContext_Image_width(ctx, field) case "height": return ec.fieldContext_Image_height(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Image", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_imageCreate_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_imageDestroy(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_imageDestroy, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().ImageDestroy(ctx, fc.Args["input"].(ImageDestroyInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "MODIFY") if err != nil { var zeroVal bool return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal bool return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_Mutation_imageDestroy(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_imageDestroy_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_newUser(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_newUser, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().NewUser(ctx, fc.Args["input"].(NewUserInput)) }, nil, ec.marshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID, true, false, ) } func (ec *executionContext) fieldContext_Mutation_newUser(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type ID does not have child fields") }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_newUser_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_activateNewUser(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_activateNewUser, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().ActivateNewUser(ctx, fc.Args["input"].(ActivateNewUserInput)) }, nil, ec.marshalOUser2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUser, true, false, ) } func (ec *executionContext) fieldContext_Mutation_activateNewUser(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_User_id(ctx, field) case "name": return ec.fieldContext_User_name(ctx, field) case "roles": return ec.fieldContext_User_roles(ctx, field) case "email": return ec.fieldContext_User_email(ctx, field) case "api_key": return ec.fieldContext_User_api_key(ctx, field) case "notification_subscriptions": return ec.fieldContext_User_notification_subscriptions(ctx, field) case "vote_count": return ec.fieldContext_User_vote_count(ctx, field) case "edit_count": return ec.fieldContext_User_edit_count(ctx, field) case "api_calls": return ec.fieldContext_User_api_calls(ctx, field) case "invited_by": return ec.fieldContext_User_invited_by(ctx, field) case "invite_tokens": return ec.fieldContext_User_invite_tokens(ctx, field) case "active_invite_codes": return ec.fieldContext_User_active_invite_codes(ctx, field) case "invite_codes": return ec.fieldContext_User_invite_codes(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type User", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_activateNewUser_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_generateInviteCode(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_generateInviteCode, func(ctx context.Context) (any, error) { return ec.Resolvers.Mutation().GenerateInviteCode(ctx) }, nil, ec.marshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID, true, false, ) } func (ec *executionContext) fieldContext_Mutation_generateInviteCode(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type ID does not have child fields") }, } return fc, nil } func (ec *executionContext) _Mutation_generateInviteCodes(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_generateInviteCodes, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().GenerateInviteCodes(ctx, fc.Args["input"].(*GenerateInviteCodeInput)) }, nil, ec.marshalNID2ᚕgithubᚗcomᚋgofrsᚋuuidᚐUUIDᚄ, true, true, ) } func (ec *executionContext) fieldContext_Mutation_generateInviteCodes(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type ID does not have child fields") }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_generateInviteCodes_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_rescindInviteCode(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_rescindInviteCode, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().RescindInviteCode(ctx, fc.Args["code"].(uuid.UUID)) }, nil, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_Mutation_rescindInviteCode(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_rescindInviteCode_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_grantInvite(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_grantInvite, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().GrantInvite(ctx, fc.Args["input"].(GrantInviteInput)) }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_Mutation_grantInvite(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_grantInvite_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_revokeInvite(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_revokeInvite, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().RevokeInvite(ctx, fc.Args["input"].(RevokeInviteInput)) }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_Mutation_revokeInvite(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_revokeInvite_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_tagCategoryCreate(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_tagCategoryCreate, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().TagCategoryCreate(ctx, fc.Args["input"].(TagCategoryCreateInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "ADMIN") if err != nil { var zeroVal *TagCategory return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *TagCategory return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalOTagCategory2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagCategory, true, false, ) } func (ec *executionContext) fieldContext_Mutation_tagCategoryCreate(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_TagCategory_id(ctx, field) case "name": return ec.fieldContext_TagCategory_name(ctx, field) case "group": return ec.fieldContext_TagCategory_group(ctx, field) case "description": return ec.fieldContext_TagCategory_description(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type TagCategory", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_tagCategoryCreate_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_tagCategoryUpdate(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_tagCategoryUpdate, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().TagCategoryUpdate(ctx, fc.Args["input"].(TagCategoryUpdateInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "ADMIN") if err != nil { var zeroVal *TagCategory return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *TagCategory return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalOTagCategory2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagCategory, true, false, ) } func (ec *executionContext) fieldContext_Mutation_tagCategoryUpdate(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_TagCategory_id(ctx, field) case "name": return ec.fieldContext_TagCategory_name(ctx, field) case "group": return ec.fieldContext_TagCategory_group(ctx, field) case "description": return ec.fieldContext_TagCategory_description(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type TagCategory", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_tagCategoryUpdate_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_tagCategoryDestroy(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_tagCategoryDestroy, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().TagCategoryDestroy(ctx, fc.Args["input"].(TagCategoryDestroyInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "ADMIN") if err != nil { var zeroVal bool return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal bool return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_Mutation_tagCategoryDestroy(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_tagCategoryDestroy_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_siteCreate(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_siteCreate, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().SiteCreate(ctx, fc.Args["input"].(SiteCreateInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "ADMIN") if err != nil { var zeroVal *Site return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *Site return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalOSite2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSite, true, false, ) } func (ec *executionContext) fieldContext_Mutation_siteCreate(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Site_id(ctx, field) case "name": return ec.fieldContext_Site_name(ctx, field) case "description": return ec.fieldContext_Site_description(ctx, field) case "url": return ec.fieldContext_Site_url(ctx, field) case "regex": return ec.fieldContext_Site_regex(ctx, field) case "valid_types": return ec.fieldContext_Site_valid_types(ctx, field) case "icon": return ec.fieldContext_Site_icon(ctx, field) case "created": return ec.fieldContext_Site_created(ctx, field) case "updated": return ec.fieldContext_Site_updated(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Site", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_siteCreate_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_siteUpdate(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_siteUpdate, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().SiteUpdate(ctx, fc.Args["input"].(SiteUpdateInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "ADMIN") if err != nil { var zeroVal *Site return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *Site return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalOSite2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSite, true, false, ) } func (ec *executionContext) fieldContext_Mutation_siteUpdate(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Site_id(ctx, field) case "name": return ec.fieldContext_Site_name(ctx, field) case "description": return ec.fieldContext_Site_description(ctx, field) case "url": return ec.fieldContext_Site_url(ctx, field) case "regex": return ec.fieldContext_Site_regex(ctx, field) case "valid_types": return ec.fieldContext_Site_valid_types(ctx, field) case "icon": return ec.fieldContext_Site_icon(ctx, field) case "created": return ec.fieldContext_Site_created(ctx, field) case "updated": return ec.fieldContext_Site_updated(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Site", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_siteUpdate_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_siteDestroy(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_siteDestroy, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().SiteDestroy(ctx, fc.Args["input"].(SiteDestroyInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "ADMIN") if err != nil { var zeroVal bool return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal bool return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_Mutation_siteDestroy(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_siteDestroy_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_regenerateAPIKey(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_regenerateAPIKey, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().RegenerateAPIKey(ctx, fc.Args["userID"].(*uuid.UUID)) }, nil, ec.marshalNString2string, true, true, ) } func (ec *executionContext) fieldContext_Mutation_regenerateAPIKey(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_regenerateAPIKey_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_resetPassword(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_resetPassword, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().ResetPassword(ctx, fc.Args["input"].(ResetPasswordInput)) }, nil, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_Mutation_resetPassword(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_resetPassword_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_changePassword(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_changePassword, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().ChangePassword(ctx, fc.Args["input"].(UserChangePasswordInput)) }, nil, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_Mutation_changePassword(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_changePassword_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_requestChangeEmail(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_requestChangeEmail, func(ctx context.Context) (any, error) { return ec.Resolvers.Mutation().RequestChangeEmail(ctx) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal UserChangeEmailStatus return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal UserChangeEmailStatus return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNUserChangeEmailStatus2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUserChangeEmailStatus, true, true, ) } func (ec *executionContext) fieldContext_Mutation_requestChangeEmail(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type UserChangeEmailStatus does not have child fields") }, } return fc, nil } func (ec *executionContext) _Mutation_validateChangeEmail(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_validateChangeEmail, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().ValidateChangeEmail(ctx, fc.Args["token"].(uuid.UUID), fc.Args["email"].(string)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal UserChangeEmailStatus return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal UserChangeEmailStatus return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNUserChangeEmailStatus2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUserChangeEmailStatus, true, true, ) } func (ec *executionContext) fieldContext_Mutation_validateChangeEmail(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type UserChangeEmailStatus does not have child fields") }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_validateChangeEmail_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_confirmChangeEmail(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_confirmChangeEmail, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().ConfirmChangeEmail(ctx, fc.Args["token"].(uuid.UUID)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal UserChangeEmailStatus return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal UserChangeEmailStatus return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNUserChangeEmailStatus2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUserChangeEmailStatus, true, true, ) } func (ec *executionContext) fieldContext_Mutation_confirmChangeEmail(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type UserChangeEmailStatus does not have child fields") }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_confirmChangeEmail_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_sceneEdit(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_sceneEdit, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().SceneEdit(ctx, fc.Args["input"].(SceneEditInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "EDIT") if err != nil { var zeroVal *Edit return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *Edit return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNEdit2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEdit, true, true, ) } func (ec *executionContext) fieldContext_Mutation_sceneEdit(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Edit_id(ctx, field) case "user": return ec.fieldContext_Edit_user(ctx, field) case "target": return ec.fieldContext_Edit_target(ctx, field) case "target_type": return ec.fieldContext_Edit_target_type(ctx, field) case "merge_sources": return ec.fieldContext_Edit_merge_sources(ctx, field) case "operation": return ec.fieldContext_Edit_operation(ctx, field) case "bot": return ec.fieldContext_Edit_bot(ctx, field) case "details": return ec.fieldContext_Edit_details(ctx, field) case "old_details": return ec.fieldContext_Edit_old_details(ctx, field) case "options": return ec.fieldContext_Edit_options(ctx, field) case "comments": return ec.fieldContext_Edit_comments(ctx, field) case "votes": return ec.fieldContext_Edit_votes(ctx, field) case "vote_count": return ec.fieldContext_Edit_vote_count(ctx, field) case "destructive": return ec.fieldContext_Edit_destructive(ctx, field) case "status": return ec.fieldContext_Edit_status(ctx, field) case "applied": return ec.fieldContext_Edit_applied(ctx, field) case "update_count": return ec.fieldContext_Edit_update_count(ctx, field) case "updatable": return ec.fieldContext_Edit_updatable(ctx, field) case "created": return ec.fieldContext_Edit_created(ctx, field) case "updated": return ec.fieldContext_Edit_updated(ctx, field) case "closed": return ec.fieldContext_Edit_closed(ctx, field) case "expires": return ec.fieldContext_Edit_expires(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Edit", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_sceneEdit_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_performerEdit(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_performerEdit, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().PerformerEdit(ctx, fc.Args["input"].(PerformerEditInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "EDIT") if err != nil { var zeroVal *Edit return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *Edit return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNEdit2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEdit, true, true, ) } func (ec *executionContext) fieldContext_Mutation_performerEdit(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Edit_id(ctx, field) case "user": return ec.fieldContext_Edit_user(ctx, field) case "target": return ec.fieldContext_Edit_target(ctx, field) case "target_type": return ec.fieldContext_Edit_target_type(ctx, field) case "merge_sources": return ec.fieldContext_Edit_merge_sources(ctx, field) case "operation": return ec.fieldContext_Edit_operation(ctx, field) case "bot": return ec.fieldContext_Edit_bot(ctx, field) case "details": return ec.fieldContext_Edit_details(ctx, field) case "old_details": return ec.fieldContext_Edit_old_details(ctx, field) case "options": return ec.fieldContext_Edit_options(ctx, field) case "comments": return ec.fieldContext_Edit_comments(ctx, field) case "votes": return ec.fieldContext_Edit_votes(ctx, field) case "vote_count": return ec.fieldContext_Edit_vote_count(ctx, field) case "destructive": return ec.fieldContext_Edit_destructive(ctx, field) case "status": return ec.fieldContext_Edit_status(ctx, field) case "applied": return ec.fieldContext_Edit_applied(ctx, field) case "update_count": return ec.fieldContext_Edit_update_count(ctx, field) case "updatable": return ec.fieldContext_Edit_updatable(ctx, field) case "created": return ec.fieldContext_Edit_created(ctx, field) case "updated": return ec.fieldContext_Edit_updated(ctx, field) case "closed": return ec.fieldContext_Edit_closed(ctx, field) case "expires": return ec.fieldContext_Edit_expires(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Edit", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_performerEdit_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_studioEdit(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_studioEdit, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().StudioEdit(ctx, fc.Args["input"].(StudioEditInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "EDIT") if err != nil { var zeroVal *Edit return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *Edit return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNEdit2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEdit, true, true, ) } func (ec *executionContext) fieldContext_Mutation_studioEdit(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Edit_id(ctx, field) case "user": return ec.fieldContext_Edit_user(ctx, field) case "target": return ec.fieldContext_Edit_target(ctx, field) case "target_type": return ec.fieldContext_Edit_target_type(ctx, field) case "merge_sources": return ec.fieldContext_Edit_merge_sources(ctx, field) case "operation": return ec.fieldContext_Edit_operation(ctx, field) case "bot": return ec.fieldContext_Edit_bot(ctx, field) case "details": return ec.fieldContext_Edit_details(ctx, field) case "old_details": return ec.fieldContext_Edit_old_details(ctx, field) case "options": return ec.fieldContext_Edit_options(ctx, field) case "comments": return ec.fieldContext_Edit_comments(ctx, field) case "votes": return ec.fieldContext_Edit_votes(ctx, field) case "vote_count": return ec.fieldContext_Edit_vote_count(ctx, field) case "destructive": return ec.fieldContext_Edit_destructive(ctx, field) case "status": return ec.fieldContext_Edit_status(ctx, field) case "applied": return ec.fieldContext_Edit_applied(ctx, field) case "update_count": return ec.fieldContext_Edit_update_count(ctx, field) case "updatable": return ec.fieldContext_Edit_updatable(ctx, field) case "created": return ec.fieldContext_Edit_created(ctx, field) case "updated": return ec.fieldContext_Edit_updated(ctx, field) case "closed": return ec.fieldContext_Edit_closed(ctx, field) case "expires": return ec.fieldContext_Edit_expires(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Edit", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_studioEdit_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_tagEdit(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_tagEdit, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().TagEdit(ctx, fc.Args["input"].(TagEditInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "EDIT") if err != nil { var zeroVal *Edit return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *Edit return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNEdit2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEdit, true, true, ) } func (ec *executionContext) fieldContext_Mutation_tagEdit(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Edit_id(ctx, field) case "user": return ec.fieldContext_Edit_user(ctx, field) case "target": return ec.fieldContext_Edit_target(ctx, field) case "target_type": return ec.fieldContext_Edit_target_type(ctx, field) case "merge_sources": return ec.fieldContext_Edit_merge_sources(ctx, field) case "operation": return ec.fieldContext_Edit_operation(ctx, field) case "bot": return ec.fieldContext_Edit_bot(ctx, field) case "details": return ec.fieldContext_Edit_details(ctx, field) case "old_details": return ec.fieldContext_Edit_old_details(ctx, field) case "options": return ec.fieldContext_Edit_options(ctx, field) case "comments": return ec.fieldContext_Edit_comments(ctx, field) case "votes": return ec.fieldContext_Edit_votes(ctx, field) case "vote_count": return ec.fieldContext_Edit_vote_count(ctx, field) case "destructive": return ec.fieldContext_Edit_destructive(ctx, field) case "status": return ec.fieldContext_Edit_status(ctx, field) case "applied": return ec.fieldContext_Edit_applied(ctx, field) case "update_count": return ec.fieldContext_Edit_update_count(ctx, field) case "updatable": return ec.fieldContext_Edit_updatable(ctx, field) case "created": return ec.fieldContext_Edit_created(ctx, field) case "updated": return ec.fieldContext_Edit_updated(ctx, field) case "closed": return ec.fieldContext_Edit_closed(ctx, field) case "expires": return ec.fieldContext_Edit_expires(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Edit", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_tagEdit_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_sceneEditUpdate(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_sceneEditUpdate, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().SceneEditUpdate(ctx, fc.Args["id"].(uuid.UUID), fc.Args["input"].(SceneEditInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "EDIT") if err != nil { var zeroVal *Edit return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *Edit return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNEdit2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEdit, true, true, ) } func (ec *executionContext) fieldContext_Mutation_sceneEditUpdate(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Edit_id(ctx, field) case "user": return ec.fieldContext_Edit_user(ctx, field) case "target": return ec.fieldContext_Edit_target(ctx, field) case "target_type": return ec.fieldContext_Edit_target_type(ctx, field) case "merge_sources": return ec.fieldContext_Edit_merge_sources(ctx, field) case "operation": return ec.fieldContext_Edit_operation(ctx, field) case "bot": return ec.fieldContext_Edit_bot(ctx, field) case "details": return ec.fieldContext_Edit_details(ctx, field) case "old_details": return ec.fieldContext_Edit_old_details(ctx, field) case "options": return ec.fieldContext_Edit_options(ctx, field) case "comments": return ec.fieldContext_Edit_comments(ctx, field) case "votes": return ec.fieldContext_Edit_votes(ctx, field) case "vote_count": return ec.fieldContext_Edit_vote_count(ctx, field) case "destructive": return ec.fieldContext_Edit_destructive(ctx, field) case "status": return ec.fieldContext_Edit_status(ctx, field) case "applied": return ec.fieldContext_Edit_applied(ctx, field) case "update_count": return ec.fieldContext_Edit_update_count(ctx, field) case "updatable": return ec.fieldContext_Edit_updatable(ctx, field) case "created": return ec.fieldContext_Edit_created(ctx, field) case "updated": return ec.fieldContext_Edit_updated(ctx, field) case "closed": return ec.fieldContext_Edit_closed(ctx, field) case "expires": return ec.fieldContext_Edit_expires(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Edit", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_sceneEditUpdate_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_performerEditUpdate(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_performerEditUpdate, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().PerformerEditUpdate(ctx, fc.Args["id"].(uuid.UUID), fc.Args["input"].(PerformerEditInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "EDIT") if err != nil { var zeroVal *Edit return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *Edit return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNEdit2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEdit, true, true, ) } func (ec *executionContext) fieldContext_Mutation_performerEditUpdate(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Edit_id(ctx, field) case "user": return ec.fieldContext_Edit_user(ctx, field) case "target": return ec.fieldContext_Edit_target(ctx, field) case "target_type": return ec.fieldContext_Edit_target_type(ctx, field) case "merge_sources": return ec.fieldContext_Edit_merge_sources(ctx, field) case "operation": return ec.fieldContext_Edit_operation(ctx, field) case "bot": return ec.fieldContext_Edit_bot(ctx, field) case "details": return ec.fieldContext_Edit_details(ctx, field) case "old_details": return ec.fieldContext_Edit_old_details(ctx, field) case "options": return ec.fieldContext_Edit_options(ctx, field) case "comments": return ec.fieldContext_Edit_comments(ctx, field) case "votes": return ec.fieldContext_Edit_votes(ctx, field) case "vote_count": return ec.fieldContext_Edit_vote_count(ctx, field) case "destructive": return ec.fieldContext_Edit_destructive(ctx, field) case "status": return ec.fieldContext_Edit_status(ctx, field) case "applied": return ec.fieldContext_Edit_applied(ctx, field) case "update_count": return ec.fieldContext_Edit_update_count(ctx, field) case "updatable": return ec.fieldContext_Edit_updatable(ctx, field) case "created": return ec.fieldContext_Edit_created(ctx, field) case "updated": return ec.fieldContext_Edit_updated(ctx, field) case "closed": return ec.fieldContext_Edit_closed(ctx, field) case "expires": return ec.fieldContext_Edit_expires(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Edit", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_performerEditUpdate_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_studioEditUpdate(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_studioEditUpdate, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().StudioEditUpdate(ctx, fc.Args["id"].(uuid.UUID), fc.Args["input"].(StudioEditInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "EDIT") if err != nil { var zeroVal *Edit return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *Edit return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNEdit2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEdit, true, true, ) } func (ec *executionContext) fieldContext_Mutation_studioEditUpdate(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Edit_id(ctx, field) case "user": return ec.fieldContext_Edit_user(ctx, field) case "target": return ec.fieldContext_Edit_target(ctx, field) case "target_type": return ec.fieldContext_Edit_target_type(ctx, field) case "merge_sources": return ec.fieldContext_Edit_merge_sources(ctx, field) case "operation": return ec.fieldContext_Edit_operation(ctx, field) case "bot": return ec.fieldContext_Edit_bot(ctx, field) case "details": return ec.fieldContext_Edit_details(ctx, field) case "old_details": return ec.fieldContext_Edit_old_details(ctx, field) case "options": return ec.fieldContext_Edit_options(ctx, field) case "comments": return ec.fieldContext_Edit_comments(ctx, field) case "votes": return ec.fieldContext_Edit_votes(ctx, field) case "vote_count": return ec.fieldContext_Edit_vote_count(ctx, field) case "destructive": return ec.fieldContext_Edit_destructive(ctx, field) case "status": return ec.fieldContext_Edit_status(ctx, field) case "applied": return ec.fieldContext_Edit_applied(ctx, field) case "update_count": return ec.fieldContext_Edit_update_count(ctx, field) case "updatable": return ec.fieldContext_Edit_updatable(ctx, field) case "created": return ec.fieldContext_Edit_created(ctx, field) case "updated": return ec.fieldContext_Edit_updated(ctx, field) case "closed": return ec.fieldContext_Edit_closed(ctx, field) case "expires": return ec.fieldContext_Edit_expires(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Edit", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_studioEditUpdate_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_tagEditUpdate(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_tagEditUpdate, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().TagEditUpdate(ctx, fc.Args["id"].(uuid.UUID), fc.Args["input"].(TagEditInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "EDIT") if err != nil { var zeroVal *Edit return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *Edit return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNEdit2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEdit, true, true, ) } func (ec *executionContext) fieldContext_Mutation_tagEditUpdate(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Edit_id(ctx, field) case "user": return ec.fieldContext_Edit_user(ctx, field) case "target": return ec.fieldContext_Edit_target(ctx, field) case "target_type": return ec.fieldContext_Edit_target_type(ctx, field) case "merge_sources": return ec.fieldContext_Edit_merge_sources(ctx, field) case "operation": return ec.fieldContext_Edit_operation(ctx, field) case "bot": return ec.fieldContext_Edit_bot(ctx, field) case "details": return ec.fieldContext_Edit_details(ctx, field) case "old_details": return ec.fieldContext_Edit_old_details(ctx, field) case "options": return ec.fieldContext_Edit_options(ctx, field) case "comments": return ec.fieldContext_Edit_comments(ctx, field) case "votes": return ec.fieldContext_Edit_votes(ctx, field) case "vote_count": return ec.fieldContext_Edit_vote_count(ctx, field) case "destructive": return ec.fieldContext_Edit_destructive(ctx, field) case "status": return ec.fieldContext_Edit_status(ctx, field) case "applied": return ec.fieldContext_Edit_applied(ctx, field) case "update_count": return ec.fieldContext_Edit_update_count(ctx, field) case "updatable": return ec.fieldContext_Edit_updatable(ctx, field) case "created": return ec.fieldContext_Edit_created(ctx, field) case "updated": return ec.fieldContext_Edit_updated(ctx, field) case "closed": return ec.fieldContext_Edit_closed(ctx, field) case "expires": return ec.fieldContext_Edit_expires(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Edit", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_tagEditUpdate_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_editVote(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_editVote, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().EditVote(ctx, fc.Args["input"].(EditVoteInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "VOTE") if err != nil { var zeroVal *Edit return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *Edit return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNEdit2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEdit, true, true, ) } func (ec *executionContext) fieldContext_Mutation_editVote(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Edit_id(ctx, field) case "user": return ec.fieldContext_Edit_user(ctx, field) case "target": return ec.fieldContext_Edit_target(ctx, field) case "target_type": return ec.fieldContext_Edit_target_type(ctx, field) case "merge_sources": return ec.fieldContext_Edit_merge_sources(ctx, field) case "operation": return ec.fieldContext_Edit_operation(ctx, field) case "bot": return ec.fieldContext_Edit_bot(ctx, field) case "details": return ec.fieldContext_Edit_details(ctx, field) case "old_details": return ec.fieldContext_Edit_old_details(ctx, field) case "options": return ec.fieldContext_Edit_options(ctx, field) case "comments": return ec.fieldContext_Edit_comments(ctx, field) case "votes": return ec.fieldContext_Edit_votes(ctx, field) case "vote_count": return ec.fieldContext_Edit_vote_count(ctx, field) case "destructive": return ec.fieldContext_Edit_destructive(ctx, field) case "status": return ec.fieldContext_Edit_status(ctx, field) case "applied": return ec.fieldContext_Edit_applied(ctx, field) case "update_count": return ec.fieldContext_Edit_update_count(ctx, field) case "updatable": return ec.fieldContext_Edit_updatable(ctx, field) case "created": return ec.fieldContext_Edit_created(ctx, field) case "updated": return ec.fieldContext_Edit_updated(ctx, field) case "closed": return ec.fieldContext_Edit_closed(ctx, field) case "expires": return ec.fieldContext_Edit_expires(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Edit", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_editVote_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_editComment(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_editComment, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().EditComment(ctx, fc.Args["input"].(EditCommentInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "EDIT") if err != nil { var zeroVal *Edit return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *Edit return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNEdit2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEdit, true, true, ) } func (ec *executionContext) fieldContext_Mutation_editComment(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Edit_id(ctx, field) case "user": return ec.fieldContext_Edit_user(ctx, field) case "target": return ec.fieldContext_Edit_target(ctx, field) case "target_type": return ec.fieldContext_Edit_target_type(ctx, field) case "merge_sources": return ec.fieldContext_Edit_merge_sources(ctx, field) case "operation": return ec.fieldContext_Edit_operation(ctx, field) case "bot": return ec.fieldContext_Edit_bot(ctx, field) case "details": return ec.fieldContext_Edit_details(ctx, field) case "old_details": return ec.fieldContext_Edit_old_details(ctx, field) case "options": return ec.fieldContext_Edit_options(ctx, field) case "comments": return ec.fieldContext_Edit_comments(ctx, field) case "votes": return ec.fieldContext_Edit_votes(ctx, field) case "vote_count": return ec.fieldContext_Edit_vote_count(ctx, field) case "destructive": return ec.fieldContext_Edit_destructive(ctx, field) case "status": return ec.fieldContext_Edit_status(ctx, field) case "applied": return ec.fieldContext_Edit_applied(ctx, field) case "update_count": return ec.fieldContext_Edit_update_count(ctx, field) case "updatable": return ec.fieldContext_Edit_updatable(ctx, field) case "created": return ec.fieldContext_Edit_created(ctx, field) case "updated": return ec.fieldContext_Edit_updated(ctx, field) case "closed": return ec.fieldContext_Edit_closed(ctx, field) case "expires": return ec.fieldContext_Edit_expires(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Edit", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_editComment_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_applyEdit(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_applyEdit, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().ApplyEdit(ctx, fc.Args["input"].(ApplyEditInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "ADMIN") if err != nil { var zeroVal *Edit return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *Edit return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNEdit2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEdit, true, true, ) } func (ec *executionContext) fieldContext_Mutation_applyEdit(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Edit_id(ctx, field) case "user": return ec.fieldContext_Edit_user(ctx, field) case "target": return ec.fieldContext_Edit_target(ctx, field) case "target_type": return ec.fieldContext_Edit_target_type(ctx, field) case "merge_sources": return ec.fieldContext_Edit_merge_sources(ctx, field) case "operation": return ec.fieldContext_Edit_operation(ctx, field) case "bot": return ec.fieldContext_Edit_bot(ctx, field) case "details": return ec.fieldContext_Edit_details(ctx, field) case "old_details": return ec.fieldContext_Edit_old_details(ctx, field) case "options": return ec.fieldContext_Edit_options(ctx, field) case "comments": return ec.fieldContext_Edit_comments(ctx, field) case "votes": return ec.fieldContext_Edit_votes(ctx, field) case "vote_count": return ec.fieldContext_Edit_vote_count(ctx, field) case "destructive": return ec.fieldContext_Edit_destructive(ctx, field) case "status": return ec.fieldContext_Edit_status(ctx, field) case "applied": return ec.fieldContext_Edit_applied(ctx, field) case "update_count": return ec.fieldContext_Edit_update_count(ctx, field) case "updatable": return ec.fieldContext_Edit_updatable(ctx, field) case "created": return ec.fieldContext_Edit_created(ctx, field) case "updated": return ec.fieldContext_Edit_updated(ctx, field) case "closed": return ec.fieldContext_Edit_closed(ctx, field) case "expires": return ec.fieldContext_Edit_expires(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Edit", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_applyEdit_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_cancelEdit(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_cancelEdit, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().CancelEdit(ctx, fc.Args["input"].(CancelEditInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "EDIT") if err != nil { var zeroVal *Edit return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *Edit return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNEdit2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEdit, true, true, ) } func (ec *executionContext) fieldContext_Mutation_cancelEdit(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Edit_id(ctx, field) case "user": return ec.fieldContext_Edit_user(ctx, field) case "target": return ec.fieldContext_Edit_target(ctx, field) case "target_type": return ec.fieldContext_Edit_target_type(ctx, field) case "merge_sources": return ec.fieldContext_Edit_merge_sources(ctx, field) case "operation": return ec.fieldContext_Edit_operation(ctx, field) case "bot": return ec.fieldContext_Edit_bot(ctx, field) case "details": return ec.fieldContext_Edit_details(ctx, field) case "old_details": return ec.fieldContext_Edit_old_details(ctx, field) case "options": return ec.fieldContext_Edit_options(ctx, field) case "comments": return ec.fieldContext_Edit_comments(ctx, field) case "votes": return ec.fieldContext_Edit_votes(ctx, field) case "vote_count": return ec.fieldContext_Edit_vote_count(ctx, field) case "destructive": return ec.fieldContext_Edit_destructive(ctx, field) case "status": return ec.fieldContext_Edit_status(ctx, field) case "applied": return ec.fieldContext_Edit_applied(ctx, field) case "update_count": return ec.fieldContext_Edit_update_count(ctx, field) case "updatable": return ec.fieldContext_Edit_updatable(ctx, field) case "created": return ec.fieldContext_Edit_created(ctx, field) case "updated": return ec.fieldContext_Edit_updated(ctx, field) case "closed": return ec.fieldContext_Edit_closed(ctx, field) case "expires": return ec.fieldContext_Edit_expires(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Edit", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_cancelEdit_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_deleteEdit(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_deleteEdit, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().DeleteEdit(ctx, fc.Args["input"].(DeleteEditInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "MODERATE") if err != nil { var zeroVal bool return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal bool return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_Mutation_deleteEdit(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_deleteEdit_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_amendEdit(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_amendEdit, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().AmendEdit(ctx, fc.Args["input"].(AmendEditInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "MODERATE") if err != nil { var zeroVal *Edit return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *Edit return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNEdit2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEdit, true, true, ) } func (ec *executionContext) fieldContext_Mutation_amendEdit(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Edit_id(ctx, field) case "user": return ec.fieldContext_Edit_user(ctx, field) case "target": return ec.fieldContext_Edit_target(ctx, field) case "target_type": return ec.fieldContext_Edit_target_type(ctx, field) case "merge_sources": return ec.fieldContext_Edit_merge_sources(ctx, field) case "operation": return ec.fieldContext_Edit_operation(ctx, field) case "bot": return ec.fieldContext_Edit_bot(ctx, field) case "details": return ec.fieldContext_Edit_details(ctx, field) case "old_details": return ec.fieldContext_Edit_old_details(ctx, field) case "options": return ec.fieldContext_Edit_options(ctx, field) case "comments": return ec.fieldContext_Edit_comments(ctx, field) case "votes": return ec.fieldContext_Edit_votes(ctx, field) case "vote_count": return ec.fieldContext_Edit_vote_count(ctx, field) case "destructive": return ec.fieldContext_Edit_destructive(ctx, field) case "status": return ec.fieldContext_Edit_status(ctx, field) case "applied": return ec.fieldContext_Edit_applied(ctx, field) case "update_count": return ec.fieldContext_Edit_update_count(ctx, field) case "updatable": return ec.fieldContext_Edit_updatable(ctx, field) case "created": return ec.fieldContext_Edit_created(ctx, field) case "updated": return ec.fieldContext_Edit_updated(ctx, field) case "closed": return ec.fieldContext_Edit_closed(ctx, field) case "expires": return ec.fieldContext_Edit_expires(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Edit", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_amendEdit_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_submitFingerprint(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_submitFingerprint, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().SubmitFingerprint(ctx, fc.Args["input"].(FingerprintSubmission)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal bool return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal bool return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_Mutation_submitFingerprint(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_submitFingerprint_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_submitFingerprints(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_submitFingerprints, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().SubmitFingerprints(ctx, fc.Args["input"].([]FingerprintBatchSubmission)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal []FingerprintSubmissionResult return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal []FingerprintSubmissionResult return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNFingerprintSubmissionResult2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintSubmissionResultᚄ, true, true, ) } func (ec *executionContext) fieldContext_Mutation_submitFingerprints(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "hash": return ec.fieldContext_FingerprintSubmissionResult_hash(ctx, field) case "scene_id": return ec.fieldContext_FingerprintSubmissionResult_scene_id(ctx, field) case "error": return ec.fieldContext_FingerprintSubmissionResult_error(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type FingerprintSubmissionResult", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_submitFingerprints_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_sceneMoveFingerprintSubmissions(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_sceneMoveFingerprintSubmissions, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().SceneMoveFingerprintSubmissions(ctx, fc.Args["input"].(MoveFingerprintSubmissionsInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "MODERATE") if err != nil { var zeroVal bool return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal bool return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_Mutation_sceneMoveFingerprintSubmissions(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_sceneMoveFingerprintSubmissions_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_sceneDeleteFingerprintSubmissions(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_sceneDeleteFingerprintSubmissions, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().SceneDeleteFingerprintSubmissions(ctx, fc.Args["input"].(DeleteFingerprintSubmissionsInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "MODERATE") if err != nil { var zeroVal bool return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal bool return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_Mutation_sceneDeleteFingerprintSubmissions(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_sceneDeleteFingerprintSubmissions_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_submitSceneDraft(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_submitSceneDraft, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().SubmitSceneDraft(ctx, fc.Args["input"].(SceneDraftInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "EDIT") if err != nil { var zeroVal *DraftSubmissionStatus return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *DraftSubmissionStatus return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNDraftSubmissionStatus2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDraftSubmissionStatus, true, true, ) } func (ec *executionContext) fieldContext_Mutation_submitSceneDraft(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_DraftSubmissionStatus_id(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type DraftSubmissionStatus", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_submitSceneDraft_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_submitPerformerDraft(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_submitPerformerDraft, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().SubmitPerformerDraft(ctx, fc.Args["input"].(PerformerDraftInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "EDIT") if err != nil { var zeroVal *DraftSubmissionStatus return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *DraftSubmissionStatus return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNDraftSubmissionStatus2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDraftSubmissionStatus, true, true, ) } func (ec *executionContext) fieldContext_Mutation_submitPerformerDraft(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_DraftSubmissionStatus_id(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type DraftSubmissionStatus", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_submitPerformerDraft_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_destroyDraft(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_destroyDraft, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().DestroyDraft(ctx, fc.Args["id"].(uuid.UUID)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "EDIT") if err != nil { var zeroVal bool return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal bool return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_Mutation_destroyDraft(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_destroyDraft_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_favoritePerformer(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_favoritePerformer, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().FavoritePerformer(ctx, fc.Args["id"].(uuid.UUID), fc.Args["favorite"].(bool)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal bool return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal bool return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_Mutation_favoritePerformer(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_favoritePerformer_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_favoriteStudio(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_favoriteStudio, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().FavoriteStudio(ctx, fc.Args["id"].(uuid.UUID), fc.Args["favorite"].(bool)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal bool return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal bool return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_Mutation_favoriteStudio(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_favoriteStudio_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_markNotificationsRead(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_markNotificationsRead, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().MarkNotificationsRead(ctx, fc.Args["notification"].(*MarkNotificationReadInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal bool return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal bool return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_Mutation_markNotificationsRead(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_markNotificationsRead_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Mutation_updateNotificationSubscriptions(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Mutation_updateNotificationSubscriptions, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Mutation().UpdateNotificationSubscriptions(ctx, fc.Args["subscriptions"].([]NotificationEnum)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal bool return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal bool return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_Mutation_updateNotificationSubscriptions(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Mutation_updateNotificationSubscriptions_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Notification_created(ctx context.Context, field graphql.CollectedField, obj *Notification) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Notification_created, func(ctx context.Context) (any, error) { return ec.Resolvers.Notification().Created(ctx, obj) }, nil, ec.marshalNTime2ᚖtimeᚐTime, true, true, ) } func (ec *executionContext) fieldContext_Notification_created(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Notification", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Time does not have child fields") }, } return fc, nil } func (ec *executionContext) _Notification_read(ctx context.Context, field graphql.CollectedField, obj *Notification) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Notification_read, func(ctx context.Context) (any, error) { return ec.Resolvers.Notification().Read(ctx, obj) }, nil, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_Notification_read(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Notification", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } return fc, nil } func (ec *executionContext) _Notification_data(ctx context.Context, field graphql.CollectedField, obj *Notification) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Notification_data, func(ctx context.Context) (any, error) { return ec.Resolvers.Notification().Data(ctx, obj) }, nil, ec.marshalNNotificationData2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐNotificationData, true, true, ) } func (ec *executionContext) fieldContext_Notification_data(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Notification", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type NotificationData does not have child fields") }, } return fc, nil } func (ec *executionContext) _Performer_id(ctx context.Context, field graphql.CollectedField, obj *Performer) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Performer_id, func(ctx context.Context) (any, error) { return obj.ID, nil }, nil, ec.marshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID, true, true, ) } func (ec *executionContext) fieldContext_Performer_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Performer", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type ID does not have child fields") }, } return fc, nil } func (ec *executionContext) _Performer_name(ctx context.Context, field graphql.CollectedField, obj *Performer) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Performer_name, func(ctx context.Context) (any, error) { return obj.Name, nil }, nil, ec.marshalNString2string, true, true, ) } func (ec *executionContext) fieldContext_Performer_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Performer", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _Performer_disambiguation(ctx context.Context, field graphql.CollectedField, obj *Performer) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Performer_disambiguation, func(ctx context.Context) (any, error) { return obj.Disambiguation, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_Performer_disambiguation(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Performer", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _Performer_aliases(ctx context.Context, field graphql.CollectedField, obj *Performer) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Performer_aliases, func(ctx context.Context) (any, error) { return ec.Resolvers.Performer().Aliases(ctx, obj) }, nil, ec.marshalNString2ᚕstringᚄ, true, true, ) } func (ec *executionContext) fieldContext_Performer_aliases(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Performer", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _Performer_gender(ctx context.Context, field graphql.CollectedField, obj *Performer) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Performer_gender, func(ctx context.Context) (any, error) { return obj.Gender, nil }, nil, ec.marshalOGenderEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐGenderEnum, true, false, ) } func (ec *executionContext) fieldContext_Performer_gender(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Performer", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type GenderEnum does not have child fields") }, } return fc, nil } func (ec *executionContext) _Performer_urls(ctx context.Context, field graphql.CollectedField, obj *Performer) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Performer_urls, func(ctx context.Context) (any, error) { return ec.Resolvers.Performer().Urls(ctx, obj) }, nil, ec.marshalNURL2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐURLᚄ, true, true, ) } func (ec *executionContext) fieldContext_Performer_urls(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Performer", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "url": return ec.fieldContext_URL_url(ctx, field) case "type": return ec.fieldContext_URL_type(ctx, field) case "site": return ec.fieldContext_URL_site(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type URL", field.Name) }, } return fc, nil } func (ec *executionContext) _Performer_birthdate(ctx context.Context, field graphql.CollectedField, obj *Performer) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Performer_birthdate, func(ctx context.Context) (any, error) { return ec.Resolvers.Performer().Birthdate(ctx, obj) }, nil, ec.marshalOFuzzyDate2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFuzzyDate, true, false, ) } func (ec *executionContext) fieldContext_Performer_birthdate(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Performer", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "date": return ec.fieldContext_FuzzyDate_date(ctx, field) case "accuracy": return ec.fieldContext_FuzzyDate_accuracy(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type FuzzyDate", field.Name) }, } return fc, nil } func (ec *executionContext) _Performer_birth_date(ctx context.Context, field graphql.CollectedField, obj *Performer) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Performer_birth_date, func(ctx context.Context) (any, error) { return obj.BirthDate, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_Performer_birth_date(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Performer", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _Performer_death_date(ctx context.Context, field graphql.CollectedField, obj *Performer) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Performer_death_date, func(ctx context.Context) (any, error) { return obj.DeathDate, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_Performer_death_date(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Performer", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _Performer_age(ctx context.Context, field graphql.CollectedField, obj *Performer) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Performer_age, func(ctx context.Context) (any, error) { return ec.Resolvers.Performer().Age(ctx, obj) }, nil, ec.marshalOInt2ᚖint, true, false, ) } func (ec *executionContext) fieldContext_Performer_age(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Performer", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _Performer_ethnicity(ctx context.Context, field graphql.CollectedField, obj *Performer) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Performer_ethnicity, func(ctx context.Context) (any, error) { return obj.Ethnicity, nil }, nil, ec.marshalOEthnicityEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEthnicityEnum, true, false, ) } func (ec *executionContext) fieldContext_Performer_ethnicity(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Performer", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type EthnicityEnum does not have child fields") }, } return fc, nil } func (ec *executionContext) _Performer_country(ctx context.Context, field graphql.CollectedField, obj *Performer) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Performer_country, func(ctx context.Context) (any, error) { return obj.Country, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_Performer_country(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Performer", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _Performer_eye_color(ctx context.Context, field graphql.CollectedField, obj *Performer) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Performer_eye_color, func(ctx context.Context) (any, error) { return obj.EyeColor, nil }, nil, ec.marshalOEyeColorEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEyeColorEnum, true, false, ) } func (ec *executionContext) fieldContext_Performer_eye_color(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Performer", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type EyeColorEnum does not have child fields") }, } return fc, nil } func (ec *executionContext) _Performer_hair_color(ctx context.Context, field graphql.CollectedField, obj *Performer) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Performer_hair_color, func(ctx context.Context) (any, error) { return obj.HairColor, nil }, nil, ec.marshalOHairColorEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐHairColorEnum, true, false, ) } func (ec *executionContext) fieldContext_Performer_hair_color(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Performer", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type HairColorEnum does not have child fields") }, } return fc, nil } func (ec *executionContext) _Performer_height(ctx context.Context, field graphql.CollectedField, obj *Performer) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Performer_height, func(ctx context.Context) (any, error) { return obj.Height, nil }, nil, ec.marshalOInt2ᚖint, true, false, ) } func (ec *executionContext) fieldContext_Performer_height(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Performer", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _Performer_measurements(ctx context.Context, field graphql.CollectedField, obj *Performer) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Performer_measurements, func(ctx context.Context) (any, error) { return ec.Resolvers.Performer().Measurements(ctx, obj) }, nil, ec.marshalNMeasurements2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐMeasurements, true, true, ) } func (ec *executionContext) fieldContext_Performer_measurements(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Performer", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "cup_size": return ec.fieldContext_Measurements_cup_size(ctx, field) case "band_size": return ec.fieldContext_Measurements_band_size(ctx, field) case "waist": return ec.fieldContext_Measurements_waist(ctx, field) case "hip": return ec.fieldContext_Measurements_hip(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Measurements", field.Name) }, } return fc, nil } func (ec *executionContext) _Performer_cup_size(ctx context.Context, field graphql.CollectedField, obj *Performer) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Performer_cup_size, func(ctx context.Context) (any, error) { return obj.CupSize, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_Performer_cup_size(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Performer", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _Performer_band_size(ctx context.Context, field graphql.CollectedField, obj *Performer) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Performer_band_size, func(ctx context.Context) (any, error) { return obj.BandSize, nil }, nil, ec.marshalOInt2ᚖint, true, false, ) } func (ec *executionContext) fieldContext_Performer_band_size(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Performer", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _Performer_waist_size(ctx context.Context, field graphql.CollectedField, obj *Performer) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Performer_waist_size, func(ctx context.Context) (any, error) { return obj.WaistSize, nil }, nil, ec.marshalOInt2ᚖint, true, false, ) } func (ec *executionContext) fieldContext_Performer_waist_size(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Performer", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _Performer_hip_size(ctx context.Context, field graphql.CollectedField, obj *Performer) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Performer_hip_size, func(ctx context.Context) (any, error) { return obj.HipSize, nil }, nil, ec.marshalOInt2ᚖint, true, false, ) } func (ec *executionContext) fieldContext_Performer_hip_size(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Performer", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _Performer_breast_type(ctx context.Context, field graphql.CollectedField, obj *Performer) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Performer_breast_type, func(ctx context.Context) (any, error) { return obj.BreastType, nil }, nil, ec.marshalOBreastTypeEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐBreastTypeEnum, true, false, ) } func (ec *executionContext) fieldContext_Performer_breast_type(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Performer", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type BreastTypeEnum does not have child fields") }, } return fc, nil } func (ec *executionContext) _Performer_career_start_year(ctx context.Context, field graphql.CollectedField, obj *Performer) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Performer_career_start_year, func(ctx context.Context) (any, error) { return obj.CareerStartYear, nil }, nil, ec.marshalOInt2ᚖint, true, false, ) } func (ec *executionContext) fieldContext_Performer_career_start_year(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Performer", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _Performer_career_end_year(ctx context.Context, field graphql.CollectedField, obj *Performer) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Performer_career_end_year, func(ctx context.Context) (any, error) { return obj.CareerEndYear, nil }, nil, ec.marshalOInt2ᚖint, true, false, ) } func (ec *executionContext) fieldContext_Performer_career_end_year(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Performer", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _Performer_tattoos(ctx context.Context, field graphql.CollectedField, obj *Performer) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Performer_tattoos, func(ctx context.Context) (any, error) { return ec.Resolvers.Performer().Tattoos(ctx, obj) }, nil, ec.marshalOBodyModification2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐBodyModificationᚄ, true, false, ) } func (ec *executionContext) fieldContext_Performer_tattoos(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Performer", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "location": return ec.fieldContext_BodyModification_location(ctx, field) case "description": return ec.fieldContext_BodyModification_description(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type BodyModification", field.Name) }, } return fc, nil } func (ec *executionContext) _Performer_piercings(ctx context.Context, field graphql.CollectedField, obj *Performer) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Performer_piercings, func(ctx context.Context) (any, error) { return ec.Resolvers.Performer().Piercings(ctx, obj) }, nil, ec.marshalOBodyModification2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐBodyModificationᚄ, true, false, ) } func (ec *executionContext) fieldContext_Performer_piercings(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Performer", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "location": return ec.fieldContext_BodyModification_location(ctx, field) case "description": return ec.fieldContext_BodyModification_description(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type BodyModification", field.Name) }, } return fc, nil } func (ec *executionContext) _Performer_images(ctx context.Context, field graphql.CollectedField, obj *Performer) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Performer_images, func(ctx context.Context) (any, error) { return ec.Resolvers.Performer().Images(ctx, obj) }, nil, ec.marshalNImage2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐImageᚄ, true, true, ) } func (ec *executionContext) fieldContext_Performer_images(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Performer", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Image_id(ctx, field) case "url": return ec.fieldContext_Image_url(ctx, field) case "width": return ec.fieldContext_Image_width(ctx, field) case "height": return ec.fieldContext_Image_height(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Image", field.Name) }, } return fc, nil } func (ec *executionContext) _Performer_deleted(ctx context.Context, field graphql.CollectedField, obj *Performer) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Performer_deleted, func(ctx context.Context) (any, error) { return obj.Deleted, nil }, nil, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_Performer_deleted(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Performer", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } return fc, nil } func (ec *executionContext) _Performer_edits(ctx context.Context, field graphql.CollectedField, obj *Performer) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Performer_edits, func(ctx context.Context) (any, error) { return ec.Resolvers.Performer().Edits(ctx, obj) }, nil, ec.marshalNEdit2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditᚄ, true, true, ) } func (ec *executionContext) fieldContext_Performer_edits(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Performer", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Edit_id(ctx, field) case "user": return ec.fieldContext_Edit_user(ctx, field) case "target": return ec.fieldContext_Edit_target(ctx, field) case "target_type": return ec.fieldContext_Edit_target_type(ctx, field) case "merge_sources": return ec.fieldContext_Edit_merge_sources(ctx, field) case "operation": return ec.fieldContext_Edit_operation(ctx, field) case "bot": return ec.fieldContext_Edit_bot(ctx, field) case "details": return ec.fieldContext_Edit_details(ctx, field) case "old_details": return ec.fieldContext_Edit_old_details(ctx, field) case "options": return ec.fieldContext_Edit_options(ctx, field) case "comments": return ec.fieldContext_Edit_comments(ctx, field) case "votes": return ec.fieldContext_Edit_votes(ctx, field) case "vote_count": return ec.fieldContext_Edit_vote_count(ctx, field) case "destructive": return ec.fieldContext_Edit_destructive(ctx, field) case "status": return ec.fieldContext_Edit_status(ctx, field) case "applied": return ec.fieldContext_Edit_applied(ctx, field) case "update_count": return ec.fieldContext_Edit_update_count(ctx, field) case "updatable": return ec.fieldContext_Edit_updatable(ctx, field) case "created": return ec.fieldContext_Edit_created(ctx, field) case "updated": return ec.fieldContext_Edit_updated(ctx, field) case "closed": return ec.fieldContext_Edit_closed(ctx, field) case "expires": return ec.fieldContext_Edit_expires(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Edit", field.Name) }, } return fc, nil } func (ec *executionContext) _Performer_scene_count(ctx context.Context, field graphql.CollectedField, obj *Performer) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Performer_scene_count, func(ctx context.Context) (any, error) { return ec.Resolvers.Performer().SceneCount(ctx, obj) }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_Performer_scene_count(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Performer", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _Performer_scenes(ctx context.Context, field graphql.CollectedField, obj *Performer) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Performer_scenes, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Performer().Scenes(ctx, obj, fc.Args["input"].(*PerformerScenesInput)) }, nil, ec.marshalNScene2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneᚄ, true, true, ) } func (ec *executionContext) fieldContext_Performer_scenes(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Performer", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Scene_id(ctx, field) case "title": return ec.fieldContext_Scene_title(ctx, field) case "details": return ec.fieldContext_Scene_details(ctx, field) case "date": return ec.fieldContext_Scene_date(ctx, field) case "release_date": return ec.fieldContext_Scene_release_date(ctx, field) case "production_date": return ec.fieldContext_Scene_production_date(ctx, field) case "urls": return ec.fieldContext_Scene_urls(ctx, field) case "studio": return ec.fieldContext_Scene_studio(ctx, field) case "tags": return ec.fieldContext_Scene_tags(ctx, field) case "images": return ec.fieldContext_Scene_images(ctx, field) case "performers": return ec.fieldContext_Scene_performers(ctx, field) case "fingerprints": return ec.fieldContext_Scene_fingerprints(ctx, field) case "duration": return ec.fieldContext_Scene_duration(ctx, field) case "director": return ec.fieldContext_Scene_director(ctx, field) case "code": return ec.fieldContext_Scene_code(ctx, field) case "deleted": return ec.fieldContext_Scene_deleted(ctx, field) case "edits": return ec.fieldContext_Scene_edits(ctx, field) case "created": return ec.fieldContext_Scene_created(ctx, field) case "updated": return ec.fieldContext_Scene_updated(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Scene", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Performer_scenes_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Performer_merged_ids(ctx context.Context, field graphql.CollectedField, obj *Performer) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Performer_merged_ids, func(ctx context.Context) (any, error) { return ec.Resolvers.Performer().MergedIds(ctx, obj) }, nil, ec.marshalNID2ᚕgithubᚗcomᚋgofrsᚋuuidᚐUUIDᚄ, true, true, ) } func (ec *executionContext) fieldContext_Performer_merged_ids(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Performer", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type ID does not have child fields") }, } return fc, nil } func (ec *executionContext) _Performer_merged_into_id(ctx context.Context, field graphql.CollectedField, obj *Performer) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Performer_merged_into_id, func(ctx context.Context) (any, error) { return ec.Resolvers.Performer().MergedIntoID(ctx, obj) }, nil, ec.marshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID, true, false, ) } func (ec *executionContext) fieldContext_Performer_merged_into_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Performer", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type ID does not have child fields") }, } return fc, nil } func (ec *executionContext) _Performer_studios(ctx context.Context, field graphql.CollectedField, obj *Performer) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Performer_studios, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Performer().Studios(ctx, obj, fc.Args["studio_id"].(*uuid.UUID)) }, nil, ec.marshalNPerformerStudio2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerStudioᚄ, true, true, ) } func (ec *executionContext) fieldContext_Performer_studios(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Performer", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "studio": return ec.fieldContext_PerformerStudio_studio(ctx, field) case "scene_count": return ec.fieldContext_PerformerStudio_scene_count(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type PerformerStudio", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Performer_studios_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Performer_is_favorite(ctx context.Context, field graphql.CollectedField, obj *Performer) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Performer_is_favorite, func(ctx context.Context) (any, error) { return ec.Resolvers.Performer().IsFavorite(ctx, obj) }, nil, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_Performer_is_favorite(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Performer", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } return fc, nil } func (ec *executionContext) _Performer_created(ctx context.Context, field graphql.CollectedField, obj *Performer) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Performer_created, func(ctx context.Context) (any, error) { return obj.Created, nil }, nil, ec.marshalNTime2timeᚐTime, true, true, ) } func (ec *executionContext) fieldContext_Performer_created(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Performer", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Time does not have child fields") }, } return fc, nil } func (ec *executionContext) _Performer_updated(ctx context.Context, field graphql.CollectedField, obj *Performer) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Performer_updated, func(ctx context.Context) (any, error) { return obj.Updated, nil }, nil, ec.marshalNTime2timeᚐTime, true, true, ) } func (ec *executionContext) fieldContext_Performer_updated(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Performer", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Time does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerAppearance_performer(ctx context.Context, field graphql.CollectedField, obj *PerformerAppearance) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerAppearance_performer, func(ctx context.Context) (any, error) { return obj.Performer, nil }, nil, ec.marshalNPerformer2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformer, true, true, ) } func (ec *executionContext) fieldContext_PerformerAppearance_performer(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerAppearance", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Performer_id(ctx, field) case "name": return ec.fieldContext_Performer_name(ctx, field) case "disambiguation": return ec.fieldContext_Performer_disambiguation(ctx, field) case "aliases": return ec.fieldContext_Performer_aliases(ctx, field) case "gender": return ec.fieldContext_Performer_gender(ctx, field) case "urls": return ec.fieldContext_Performer_urls(ctx, field) case "birthdate": return ec.fieldContext_Performer_birthdate(ctx, field) case "birth_date": return ec.fieldContext_Performer_birth_date(ctx, field) case "death_date": return ec.fieldContext_Performer_death_date(ctx, field) case "age": return ec.fieldContext_Performer_age(ctx, field) case "ethnicity": return ec.fieldContext_Performer_ethnicity(ctx, field) case "country": return ec.fieldContext_Performer_country(ctx, field) case "eye_color": return ec.fieldContext_Performer_eye_color(ctx, field) case "hair_color": return ec.fieldContext_Performer_hair_color(ctx, field) case "height": return ec.fieldContext_Performer_height(ctx, field) case "measurements": return ec.fieldContext_Performer_measurements(ctx, field) case "cup_size": return ec.fieldContext_Performer_cup_size(ctx, field) case "band_size": return ec.fieldContext_Performer_band_size(ctx, field) case "waist_size": return ec.fieldContext_Performer_waist_size(ctx, field) case "hip_size": return ec.fieldContext_Performer_hip_size(ctx, field) case "breast_type": return ec.fieldContext_Performer_breast_type(ctx, field) case "career_start_year": return ec.fieldContext_Performer_career_start_year(ctx, field) case "career_end_year": return ec.fieldContext_Performer_career_end_year(ctx, field) case "tattoos": return ec.fieldContext_Performer_tattoos(ctx, field) case "piercings": return ec.fieldContext_Performer_piercings(ctx, field) case "images": return ec.fieldContext_Performer_images(ctx, field) case "deleted": return ec.fieldContext_Performer_deleted(ctx, field) case "edits": return ec.fieldContext_Performer_edits(ctx, field) case "scene_count": return ec.fieldContext_Performer_scene_count(ctx, field) case "scenes": return ec.fieldContext_Performer_scenes(ctx, field) case "merged_ids": return ec.fieldContext_Performer_merged_ids(ctx, field) case "merged_into_id": return ec.fieldContext_Performer_merged_into_id(ctx, field) case "studios": return ec.fieldContext_Performer_studios(ctx, field) case "is_favorite": return ec.fieldContext_Performer_is_favorite(ctx, field) case "created": return ec.fieldContext_Performer_created(ctx, field) case "updated": return ec.fieldContext_Performer_updated(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Performer", field.Name) }, } return fc, nil } func (ec *executionContext) _PerformerAppearance_as(ctx context.Context, field graphql.CollectedField, obj *PerformerAppearance) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerAppearance_as, func(ctx context.Context) (any, error) { return obj.As, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_PerformerAppearance_as(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerAppearance", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerDraft_id(ctx context.Context, field graphql.CollectedField, obj *PerformerDraft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerDraft_id, func(ctx context.Context) (any, error) { return obj.ID, nil }, nil, ec.marshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID, true, false, ) } func (ec *executionContext) fieldContext_PerformerDraft_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerDraft", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type ID does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerDraft_name(ctx context.Context, field graphql.CollectedField, obj *PerformerDraft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerDraft_name, func(ctx context.Context) (any, error) { return obj.Name, nil }, nil, ec.marshalNString2string, true, true, ) } func (ec *executionContext) fieldContext_PerformerDraft_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerDraft", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerDraft_disambiguation(ctx context.Context, field graphql.CollectedField, obj *PerformerDraft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerDraft_disambiguation, func(ctx context.Context) (any, error) { return obj.Disambiguation, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_PerformerDraft_disambiguation(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerDraft", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerDraft_aliases(ctx context.Context, field graphql.CollectedField, obj *PerformerDraft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerDraft_aliases, func(ctx context.Context) (any, error) { return obj.Aliases, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_PerformerDraft_aliases(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerDraft", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerDraft_gender(ctx context.Context, field graphql.CollectedField, obj *PerformerDraft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerDraft_gender, func(ctx context.Context) (any, error) { return obj.Gender, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_PerformerDraft_gender(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerDraft", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerDraft_birthdate(ctx context.Context, field graphql.CollectedField, obj *PerformerDraft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerDraft_birthdate, func(ctx context.Context) (any, error) { return obj.Birthdate, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_PerformerDraft_birthdate(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerDraft", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerDraft_deathdate(ctx context.Context, field graphql.CollectedField, obj *PerformerDraft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerDraft_deathdate, func(ctx context.Context) (any, error) { return obj.Deathdate, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_PerformerDraft_deathdate(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerDraft", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerDraft_urls(ctx context.Context, field graphql.CollectedField, obj *PerformerDraft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerDraft_urls, func(ctx context.Context) (any, error) { return obj.Urls, nil }, nil, ec.marshalOString2ᚕstringᚄ, true, false, ) } func (ec *executionContext) fieldContext_PerformerDraft_urls(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerDraft", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerDraft_ethnicity(ctx context.Context, field graphql.CollectedField, obj *PerformerDraft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerDraft_ethnicity, func(ctx context.Context) (any, error) { return obj.Ethnicity, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_PerformerDraft_ethnicity(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerDraft", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerDraft_country(ctx context.Context, field graphql.CollectedField, obj *PerformerDraft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerDraft_country, func(ctx context.Context) (any, error) { return obj.Country, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_PerformerDraft_country(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerDraft", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerDraft_eye_color(ctx context.Context, field graphql.CollectedField, obj *PerformerDraft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerDraft_eye_color, func(ctx context.Context) (any, error) { return obj.EyeColor, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_PerformerDraft_eye_color(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerDraft", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerDraft_hair_color(ctx context.Context, field graphql.CollectedField, obj *PerformerDraft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerDraft_hair_color, func(ctx context.Context) (any, error) { return obj.HairColor, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_PerformerDraft_hair_color(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerDraft", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerDraft_height(ctx context.Context, field graphql.CollectedField, obj *PerformerDraft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerDraft_height, func(ctx context.Context) (any, error) { return obj.Height, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_PerformerDraft_height(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerDraft", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerDraft_measurements(ctx context.Context, field graphql.CollectedField, obj *PerformerDraft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerDraft_measurements, func(ctx context.Context) (any, error) { return obj.Measurements, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_PerformerDraft_measurements(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerDraft", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerDraft_breast_type(ctx context.Context, field graphql.CollectedField, obj *PerformerDraft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerDraft_breast_type, func(ctx context.Context) (any, error) { return obj.BreastType, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_PerformerDraft_breast_type(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerDraft", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerDraft_tattoos(ctx context.Context, field graphql.CollectedField, obj *PerformerDraft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerDraft_tattoos, func(ctx context.Context) (any, error) { return obj.Tattoos, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_PerformerDraft_tattoos(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerDraft", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerDraft_piercings(ctx context.Context, field graphql.CollectedField, obj *PerformerDraft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerDraft_piercings, func(ctx context.Context) (any, error) { return obj.Piercings, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_PerformerDraft_piercings(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerDraft", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerDraft_career_start_year(ctx context.Context, field graphql.CollectedField, obj *PerformerDraft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerDraft_career_start_year, func(ctx context.Context) (any, error) { return obj.CareerStartYear, nil }, nil, ec.marshalOInt2ᚖint, true, false, ) } func (ec *executionContext) fieldContext_PerformerDraft_career_start_year(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerDraft", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerDraft_career_end_year(ctx context.Context, field graphql.CollectedField, obj *PerformerDraft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerDraft_career_end_year, func(ctx context.Context) (any, error) { return obj.CareerEndYear, nil }, nil, ec.marshalOInt2ᚖint, true, false, ) } func (ec *executionContext) fieldContext_PerformerDraft_career_end_year(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerDraft", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerDraft_image(ctx context.Context, field graphql.CollectedField, obj *PerformerDraft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerDraft_image, func(ctx context.Context) (any, error) { return ec.Resolvers.PerformerDraft().Image(ctx, obj) }, nil, ec.marshalOImage2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐImage, true, false, ) } func (ec *executionContext) fieldContext_PerformerDraft_image(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerDraft", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Image_id(ctx, field) case "url": return ec.fieldContext_Image_url(ctx, field) case "width": return ec.fieldContext_Image_width(ctx, field) case "height": return ec.fieldContext_Image_height(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Image", field.Name) }, } return fc, nil } func (ec *executionContext) _PerformerEdit_name(ctx context.Context, field graphql.CollectedField, obj *PerformerEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerEdit_name, func(ctx context.Context) (any, error) { return obj.Name, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_PerformerEdit_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerEdit_disambiguation(ctx context.Context, field graphql.CollectedField, obj *PerformerEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerEdit_disambiguation, func(ctx context.Context) (any, error) { return obj.Disambiguation, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_PerformerEdit_disambiguation(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerEdit_added_aliases(ctx context.Context, field graphql.CollectedField, obj *PerformerEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerEdit_added_aliases, func(ctx context.Context) (any, error) { return obj.AddedAliases, nil }, nil, ec.marshalOString2ᚕstringᚄ, true, false, ) } func (ec *executionContext) fieldContext_PerformerEdit_added_aliases(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerEdit_removed_aliases(ctx context.Context, field graphql.CollectedField, obj *PerformerEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerEdit_removed_aliases, func(ctx context.Context) (any, error) { return obj.RemovedAliases, nil }, nil, ec.marshalOString2ᚕstringᚄ, true, false, ) } func (ec *executionContext) fieldContext_PerformerEdit_removed_aliases(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerEdit_gender(ctx context.Context, field graphql.CollectedField, obj *PerformerEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerEdit_gender, func(ctx context.Context) (any, error) { return ec.Resolvers.PerformerEdit().Gender(ctx, obj) }, nil, ec.marshalOGenderEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐGenderEnum, true, false, ) } func (ec *executionContext) fieldContext_PerformerEdit_gender(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerEdit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type GenderEnum does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerEdit_added_urls(ctx context.Context, field graphql.CollectedField, obj *PerformerEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerEdit_added_urls, func(ctx context.Context) (any, error) { return obj.AddedUrls, nil }, nil, ec.marshalOURL2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐURLᚄ, true, false, ) } func (ec *executionContext) fieldContext_PerformerEdit_added_urls(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "url": return ec.fieldContext_URL_url(ctx, field) case "type": return ec.fieldContext_URL_type(ctx, field) case "site": return ec.fieldContext_URL_site(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type URL", field.Name) }, } return fc, nil } func (ec *executionContext) _PerformerEdit_removed_urls(ctx context.Context, field graphql.CollectedField, obj *PerformerEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerEdit_removed_urls, func(ctx context.Context) (any, error) { return obj.RemovedUrls, nil }, nil, ec.marshalOURL2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐURLᚄ, true, false, ) } func (ec *executionContext) fieldContext_PerformerEdit_removed_urls(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "url": return ec.fieldContext_URL_url(ctx, field) case "type": return ec.fieldContext_URL_type(ctx, field) case "site": return ec.fieldContext_URL_site(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type URL", field.Name) }, } return fc, nil } func (ec *executionContext) _PerformerEdit_birthdate(ctx context.Context, field graphql.CollectedField, obj *PerformerEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerEdit_birthdate, func(ctx context.Context) (any, error) { return obj.Birthdate, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_PerformerEdit_birthdate(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerEdit_deathdate(ctx context.Context, field graphql.CollectedField, obj *PerformerEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerEdit_deathdate, func(ctx context.Context) (any, error) { return obj.Deathdate, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_PerformerEdit_deathdate(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerEdit_ethnicity(ctx context.Context, field graphql.CollectedField, obj *PerformerEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerEdit_ethnicity, func(ctx context.Context) (any, error) { return ec.Resolvers.PerformerEdit().Ethnicity(ctx, obj) }, nil, ec.marshalOEthnicityEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEthnicityEnum, true, false, ) } func (ec *executionContext) fieldContext_PerformerEdit_ethnicity(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerEdit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type EthnicityEnum does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerEdit_country(ctx context.Context, field graphql.CollectedField, obj *PerformerEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerEdit_country, func(ctx context.Context) (any, error) { return obj.Country, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_PerformerEdit_country(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerEdit_eye_color(ctx context.Context, field graphql.CollectedField, obj *PerformerEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerEdit_eye_color, func(ctx context.Context) (any, error) { return ec.Resolvers.PerformerEdit().EyeColor(ctx, obj) }, nil, ec.marshalOEyeColorEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEyeColorEnum, true, false, ) } func (ec *executionContext) fieldContext_PerformerEdit_eye_color(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerEdit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type EyeColorEnum does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerEdit_hair_color(ctx context.Context, field graphql.CollectedField, obj *PerformerEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerEdit_hair_color, func(ctx context.Context) (any, error) { return ec.Resolvers.PerformerEdit().HairColor(ctx, obj) }, nil, ec.marshalOHairColorEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐHairColorEnum, true, false, ) } func (ec *executionContext) fieldContext_PerformerEdit_hair_color(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerEdit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type HairColorEnum does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerEdit_height(ctx context.Context, field graphql.CollectedField, obj *PerformerEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerEdit_height, func(ctx context.Context) (any, error) { return obj.Height, nil }, nil, ec.marshalOInt2ᚖint, true, false, ) } func (ec *executionContext) fieldContext_PerformerEdit_height(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerEdit_cup_size(ctx context.Context, field graphql.CollectedField, obj *PerformerEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerEdit_cup_size, func(ctx context.Context) (any, error) { return obj.CupSize, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_PerformerEdit_cup_size(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerEdit_band_size(ctx context.Context, field graphql.CollectedField, obj *PerformerEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerEdit_band_size, func(ctx context.Context) (any, error) { return obj.BandSize, nil }, nil, ec.marshalOInt2ᚖint, true, false, ) } func (ec *executionContext) fieldContext_PerformerEdit_band_size(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerEdit_waist_size(ctx context.Context, field graphql.CollectedField, obj *PerformerEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerEdit_waist_size, func(ctx context.Context) (any, error) { return obj.WaistSize, nil }, nil, ec.marshalOInt2ᚖint, true, false, ) } func (ec *executionContext) fieldContext_PerformerEdit_waist_size(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerEdit_hip_size(ctx context.Context, field graphql.CollectedField, obj *PerformerEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerEdit_hip_size, func(ctx context.Context) (any, error) { return obj.HipSize, nil }, nil, ec.marshalOInt2ᚖint, true, false, ) } func (ec *executionContext) fieldContext_PerformerEdit_hip_size(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerEdit_breast_type(ctx context.Context, field graphql.CollectedField, obj *PerformerEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerEdit_breast_type, func(ctx context.Context) (any, error) { return ec.Resolvers.PerformerEdit().BreastType(ctx, obj) }, nil, ec.marshalOBreastTypeEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐBreastTypeEnum, true, false, ) } func (ec *executionContext) fieldContext_PerformerEdit_breast_type(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerEdit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type BreastTypeEnum does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerEdit_career_start_year(ctx context.Context, field graphql.CollectedField, obj *PerformerEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerEdit_career_start_year, func(ctx context.Context) (any, error) { return obj.CareerStartYear, nil }, nil, ec.marshalOInt2ᚖint, true, false, ) } func (ec *executionContext) fieldContext_PerformerEdit_career_start_year(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerEdit_career_end_year(ctx context.Context, field graphql.CollectedField, obj *PerformerEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerEdit_career_end_year, func(ctx context.Context) (any, error) { return obj.CareerEndYear, nil }, nil, ec.marshalOInt2ᚖint, true, false, ) } func (ec *executionContext) fieldContext_PerformerEdit_career_end_year(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerEdit_added_tattoos(ctx context.Context, field graphql.CollectedField, obj *PerformerEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerEdit_added_tattoos, func(ctx context.Context) (any, error) { return obj.AddedTattoos, nil }, nil, ec.marshalOBodyModification2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐBodyModificationᚄ, true, false, ) } func (ec *executionContext) fieldContext_PerformerEdit_added_tattoos(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "location": return ec.fieldContext_BodyModification_location(ctx, field) case "description": return ec.fieldContext_BodyModification_description(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type BodyModification", field.Name) }, } return fc, nil } func (ec *executionContext) _PerformerEdit_removed_tattoos(ctx context.Context, field graphql.CollectedField, obj *PerformerEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerEdit_removed_tattoos, func(ctx context.Context) (any, error) { return obj.RemovedTattoos, nil }, nil, ec.marshalOBodyModification2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐBodyModificationᚄ, true, false, ) } func (ec *executionContext) fieldContext_PerformerEdit_removed_tattoos(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "location": return ec.fieldContext_BodyModification_location(ctx, field) case "description": return ec.fieldContext_BodyModification_description(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type BodyModification", field.Name) }, } return fc, nil } func (ec *executionContext) _PerformerEdit_added_piercings(ctx context.Context, field graphql.CollectedField, obj *PerformerEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerEdit_added_piercings, func(ctx context.Context) (any, error) { return obj.AddedPiercings, nil }, nil, ec.marshalOBodyModification2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐBodyModificationᚄ, true, false, ) } func (ec *executionContext) fieldContext_PerformerEdit_added_piercings(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "location": return ec.fieldContext_BodyModification_location(ctx, field) case "description": return ec.fieldContext_BodyModification_description(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type BodyModification", field.Name) }, } return fc, nil } func (ec *executionContext) _PerformerEdit_removed_piercings(ctx context.Context, field graphql.CollectedField, obj *PerformerEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerEdit_removed_piercings, func(ctx context.Context) (any, error) { return obj.RemovedPiercings, nil }, nil, ec.marshalOBodyModification2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐBodyModificationᚄ, true, false, ) } func (ec *executionContext) fieldContext_PerformerEdit_removed_piercings(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "location": return ec.fieldContext_BodyModification_location(ctx, field) case "description": return ec.fieldContext_BodyModification_description(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type BodyModification", field.Name) }, } return fc, nil } func (ec *executionContext) _PerformerEdit_added_images(ctx context.Context, field graphql.CollectedField, obj *PerformerEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerEdit_added_images, func(ctx context.Context) (any, error) { return ec.Resolvers.PerformerEdit().AddedImages(ctx, obj) }, nil, ec.marshalOImage2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐImageᚄ, true, false, ) } func (ec *executionContext) fieldContext_PerformerEdit_added_images(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerEdit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Image_id(ctx, field) case "url": return ec.fieldContext_Image_url(ctx, field) case "width": return ec.fieldContext_Image_width(ctx, field) case "height": return ec.fieldContext_Image_height(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Image", field.Name) }, } return fc, nil } func (ec *executionContext) _PerformerEdit_removed_images(ctx context.Context, field graphql.CollectedField, obj *PerformerEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerEdit_removed_images, func(ctx context.Context) (any, error) { return ec.Resolvers.PerformerEdit().RemovedImages(ctx, obj) }, nil, ec.marshalOImage2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐImageᚄ, true, false, ) } func (ec *executionContext) fieldContext_PerformerEdit_removed_images(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerEdit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Image_id(ctx, field) case "url": return ec.fieldContext_Image_url(ctx, field) case "width": return ec.fieldContext_Image_width(ctx, field) case "height": return ec.fieldContext_Image_height(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Image", field.Name) }, } return fc, nil } func (ec *executionContext) _PerformerEdit_draft_id(ctx context.Context, field graphql.CollectedField, obj *PerformerEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerEdit_draft_id, func(ctx context.Context) (any, error) { return obj.DraftID, nil }, nil, ec.marshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID, true, false, ) } func (ec *executionContext) fieldContext_PerformerEdit_draft_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type ID does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerEdit_aliases(ctx context.Context, field graphql.CollectedField, obj *PerformerEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerEdit_aliases, func(ctx context.Context) (any, error) { return ec.Resolvers.PerformerEdit().Aliases(ctx, obj) }, nil, ec.marshalNString2ᚕstringᚄ, true, true, ) } func (ec *executionContext) fieldContext_PerformerEdit_aliases(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerEdit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerEdit_urls(ctx context.Context, field graphql.CollectedField, obj *PerformerEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerEdit_urls, func(ctx context.Context) (any, error) { return ec.Resolvers.PerformerEdit().Urls(ctx, obj) }, nil, ec.marshalNURL2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐURLᚄ, true, true, ) } func (ec *executionContext) fieldContext_PerformerEdit_urls(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerEdit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "url": return ec.fieldContext_URL_url(ctx, field) case "type": return ec.fieldContext_URL_type(ctx, field) case "site": return ec.fieldContext_URL_site(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type URL", field.Name) }, } return fc, nil } func (ec *executionContext) _PerformerEdit_images(ctx context.Context, field graphql.CollectedField, obj *PerformerEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerEdit_images, func(ctx context.Context) (any, error) { return ec.Resolvers.PerformerEdit().Images(ctx, obj) }, nil, ec.marshalNImage2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐImageᚄ, true, true, ) } func (ec *executionContext) fieldContext_PerformerEdit_images(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerEdit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Image_id(ctx, field) case "url": return ec.fieldContext_Image_url(ctx, field) case "width": return ec.fieldContext_Image_width(ctx, field) case "height": return ec.fieldContext_Image_height(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Image", field.Name) }, } return fc, nil } func (ec *executionContext) _PerformerEdit_tattoos(ctx context.Context, field graphql.CollectedField, obj *PerformerEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerEdit_tattoos, func(ctx context.Context) (any, error) { return ec.Resolvers.PerformerEdit().Tattoos(ctx, obj) }, nil, ec.marshalNBodyModification2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐBodyModificationᚄ, true, true, ) } func (ec *executionContext) fieldContext_PerformerEdit_tattoos(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerEdit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "location": return ec.fieldContext_BodyModification_location(ctx, field) case "description": return ec.fieldContext_BodyModification_description(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type BodyModification", field.Name) }, } return fc, nil } func (ec *executionContext) _PerformerEdit_piercings(ctx context.Context, field graphql.CollectedField, obj *PerformerEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerEdit_piercings, func(ctx context.Context) (any, error) { return ec.Resolvers.PerformerEdit().Piercings(ctx, obj) }, nil, ec.marshalNBodyModification2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐBodyModificationᚄ, true, true, ) } func (ec *executionContext) fieldContext_PerformerEdit_piercings(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerEdit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "location": return ec.fieldContext_BodyModification_location(ctx, field) case "description": return ec.fieldContext_BodyModification_description(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type BodyModification", field.Name) }, } return fc, nil } func (ec *executionContext) _PerformerEditOptions_set_modify_aliases(ctx context.Context, field graphql.CollectedField, obj *PerformerEditOptions) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerEditOptions_set_modify_aliases, func(ctx context.Context) (any, error) { return obj.SetModifyAliases, nil }, nil, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_PerformerEditOptions_set_modify_aliases(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerEditOptions", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerEditOptions_set_merge_aliases(ctx context.Context, field graphql.CollectedField, obj *PerformerEditOptions) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerEditOptions_set_merge_aliases, func(ctx context.Context) (any, error) { return obj.SetMergeAliases, nil }, nil, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_PerformerEditOptions_set_merge_aliases(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerEditOptions", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } return fc, nil } func (ec *executionContext) _PerformerSearchFacets_genders(ctx context.Context, field graphql.CollectedField, obj *PerformerSearchFacets) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerSearchFacets_genders, func(ctx context.Context) (any, error) { return obj.Genders, nil }, nil, ec.marshalNGenderFacet2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐGenderFacetᚄ, true, true, ) } func (ec *executionContext) fieldContext_PerformerSearchFacets_genders(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerSearchFacets", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "gender": return ec.fieldContext_GenderFacet_gender(ctx, field) case "count": return ec.fieldContext_GenderFacet_count(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type GenderFacet", field.Name) }, } return fc, nil } func (ec *executionContext) _PerformerStudio_studio(ctx context.Context, field graphql.CollectedField, obj *PerformerStudio) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerStudio_studio, func(ctx context.Context) (any, error) { return obj.Studio, nil }, nil, ec.marshalNStudio2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStudio, true, true, ) } func (ec *executionContext) fieldContext_PerformerStudio_studio(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerStudio", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Studio_id(ctx, field) case "name": return ec.fieldContext_Studio_name(ctx, field) case "aliases": return ec.fieldContext_Studio_aliases(ctx, field) case "urls": return ec.fieldContext_Studio_urls(ctx, field) case "parent": return ec.fieldContext_Studio_parent(ctx, field) case "child_studios": return ec.fieldContext_Studio_child_studios(ctx, field) case "sub_studios": return ec.fieldContext_Studio_sub_studios(ctx, field) case "images": return ec.fieldContext_Studio_images(ctx, field) case "deleted": return ec.fieldContext_Studio_deleted(ctx, field) case "is_favorite": return ec.fieldContext_Studio_is_favorite(ctx, field) case "created": return ec.fieldContext_Studio_created(ctx, field) case "updated": return ec.fieldContext_Studio_updated(ctx, field) case "performers": return ec.fieldContext_Studio_performers(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Studio", field.Name) }, } return fc, nil } func (ec *executionContext) _PerformerStudio_scene_count(ctx context.Context, field graphql.CollectedField, obj *PerformerStudio) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_PerformerStudio_scene_count, func(ctx context.Context) (any, error) { return obj.SceneCount, nil }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_PerformerStudio_scene_count(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "PerformerStudio", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _Query_findPerformer(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Query_findPerformer, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Query().FindPerformer(ctx, fc.Args["id"].(uuid.UUID)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal *Performer return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *Performer return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalOPerformer2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformer, true, false, ) } func (ec *executionContext) fieldContext_Query_findPerformer(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Performer_id(ctx, field) case "name": return ec.fieldContext_Performer_name(ctx, field) case "disambiguation": return ec.fieldContext_Performer_disambiguation(ctx, field) case "aliases": return ec.fieldContext_Performer_aliases(ctx, field) case "gender": return ec.fieldContext_Performer_gender(ctx, field) case "urls": return ec.fieldContext_Performer_urls(ctx, field) case "birthdate": return ec.fieldContext_Performer_birthdate(ctx, field) case "birth_date": return ec.fieldContext_Performer_birth_date(ctx, field) case "death_date": return ec.fieldContext_Performer_death_date(ctx, field) case "age": return ec.fieldContext_Performer_age(ctx, field) case "ethnicity": return ec.fieldContext_Performer_ethnicity(ctx, field) case "country": return ec.fieldContext_Performer_country(ctx, field) case "eye_color": return ec.fieldContext_Performer_eye_color(ctx, field) case "hair_color": return ec.fieldContext_Performer_hair_color(ctx, field) case "height": return ec.fieldContext_Performer_height(ctx, field) case "measurements": return ec.fieldContext_Performer_measurements(ctx, field) case "cup_size": return ec.fieldContext_Performer_cup_size(ctx, field) case "band_size": return ec.fieldContext_Performer_band_size(ctx, field) case "waist_size": return ec.fieldContext_Performer_waist_size(ctx, field) case "hip_size": return ec.fieldContext_Performer_hip_size(ctx, field) case "breast_type": return ec.fieldContext_Performer_breast_type(ctx, field) case "career_start_year": return ec.fieldContext_Performer_career_start_year(ctx, field) case "career_end_year": return ec.fieldContext_Performer_career_end_year(ctx, field) case "tattoos": return ec.fieldContext_Performer_tattoos(ctx, field) case "piercings": return ec.fieldContext_Performer_piercings(ctx, field) case "images": return ec.fieldContext_Performer_images(ctx, field) case "deleted": return ec.fieldContext_Performer_deleted(ctx, field) case "edits": return ec.fieldContext_Performer_edits(ctx, field) case "scene_count": return ec.fieldContext_Performer_scene_count(ctx, field) case "scenes": return ec.fieldContext_Performer_scenes(ctx, field) case "merged_ids": return ec.fieldContext_Performer_merged_ids(ctx, field) case "merged_into_id": return ec.fieldContext_Performer_merged_into_id(ctx, field) case "studios": return ec.fieldContext_Performer_studios(ctx, field) case "is_favorite": return ec.fieldContext_Performer_is_favorite(ctx, field) case "created": return ec.fieldContext_Performer_created(ctx, field) case "updated": return ec.fieldContext_Performer_updated(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Performer", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Query_findPerformer_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Query_queryPerformers(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Query_queryPerformers, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Query().QueryPerformers(ctx, fc.Args["input"].(PerformerQueryInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal *PerformerQuery return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *PerformerQuery return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNQueryPerformersResultType2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerQuery, true, true, ) } func (ec *executionContext) fieldContext_Query_queryPerformers(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "count": return ec.fieldContext_QueryPerformersResultType_count(ctx, field) case "performers": return ec.fieldContext_QueryPerformersResultType_performers(ctx, field) case "facets": return ec.fieldContext_QueryPerformersResultType_facets(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type QueryPerformersResultType", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Query_queryPerformers_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Query_findStudio(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Query_findStudio, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Query().FindStudio(ctx, fc.Args["id"].(*uuid.UUID), fc.Args["name"].(*string)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal *Studio return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *Studio return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalOStudio2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStudio, true, false, ) } func (ec *executionContext) fieldContext_Query_findStudio(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Studio_id(ctx, field) case "name": return ec.fieldContext_Studio_name(ctx, field) case "aliases": return ec.fieldContext_Studio_aliases(ctx, field) case "urls": return ec.fieldContext_Studio_urls(ctx, field) case "parent": return ec.fieldContext_Studio_parent(ctx, field) case "child_studios": return ec.fieldContext_Studio_child_studios(ctx, field) case "sub_studios": return ec.fieldContext_Studio_sub_studios(ctx, field) case "images": return ec.fieldContext_Studio_images(ctx, field) case "deleted": return ec.fieldContext_Studio_deleted(ctx, field) case "is_favorite": return ec.fieldContext_Studio_is_favorite(ctx, field) case "created": return ec.fieldContext_Studio_created(ctx, field) case "updated": return ec.fieldContext_Studio_updated(ctx, field) case "performers": return ec.fieldContext_Studio_performers(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Studio", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Query_findStudio_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Query_queryStudios(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Query_queryStudios, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Query().QueryStudios(ctx, fc.Args["input"].(StudioQueryInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal *QueryStudiosResultType return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *QueryStudiosResultType return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNQueryStudiosResultType2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐQueryStudiosResultType, true, true, ) } func (ec *executionContext) fieldContext_Query_queryStudios(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "count": return ec.fieldContext_QueryStudiosResultType_count(ctx, field) case "studios": return ec.fieldContext_QueryStudiosResultType_studios(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type QueryStudiosResultType", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Query_queryStudios_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Query_findTag(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Query_findTag, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Query().FindTag(ctx, fc.Args["id"].(*uuid.UUID), fc.Args["name"].(*string)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal *Tag return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *Tag return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalOTag2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTag, true, false, ) } func (ec *executionContext) fieldContext_Query_findTag(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Tag_id(ctx, field) case "name": return ec.fieldContext_Tag_name(ctx, field) case "description": return ec.fieldContext_Tag_description(ctx, field) case "aliases": return ec.fieldContext_Tag_aliases(ctx, field) case "deleted": return ec.fieldContext_Tag_deleted(ctx, field) case "edits": return ec.fieldContext_Tag_edits(ctx, field) case "category": return ec.fieldContext_Tag_category(ctx, field) case "created": return ec.fieldContext_Tag_created(ctx, field) case "updated": return ec.fieldContext_Tag_updated(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Tag", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Query_findTag_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Query_findTagOrAlias(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Query_findTagOrAlias, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Query().FindTagOrAlias(ctx, fc.Args["name"].(string)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal *Tag return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *Tag return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalOTag2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTag, true, false, ) } func (ec *executionContext) fieldContext_Query_findTagOrAlias(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Tag_id(ctx, field) case "name": return ec.fieldContext_Tag_name(ctx, field) case "description": return ec.fieldContext_Tag_description(ctx, field) case "aliases": return ec.fieldContext_Tag_aliases(ctx, field) case "deleted": return ec.fieldContext_Tag_deleted(ctx, field) case "edits": return ec.fieldContext_Tag_edits(ctx, field) case "category": return ec.fieldContext_Tag_category(ctx, field) case "created": return ec.fieldContext_Tag_created(ctx, field) case "updated": return ec.fieldContext_Tag_updated(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Tag", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Query_findTagOrAlias_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Query_queryTags(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Query_queryTags, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Query().QueryTags(ctx, fc.Args["input"].(TagQueryInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal *QueryTagsResultType return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *QueryTagsResultType return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNQueryTagsResultType2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐQueryTagsResultType, true, true, ) } func (ec *executionContext) fieldContext_Query_queryTags(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "count": return ec.fieldContext_QueryTagsResultType_count(ctx, field) case "tags": return ec.fieldContext_QueryTagsResultType_tags(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type QueryTagsResultType", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Query_queryTags_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Query_findTagCategory(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Query_findTagCategory, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Query().FindTagCategory(ctx, fc.Args["id"].(uuid.UUID)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal *TagCategory return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *TagCategory return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalOTagCategory2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagCategory, true, false, ) } func (ec *executionContext) fieldContext_Query_findTagCategory(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_TagCategory_id(ctx, field) case "name": return ec.fieldContext_TagCategory_name(ctx, field) case "group": return ec.fieldContext_TagCategory_group(ctx, field) case "description": return ec.fieldContext_TagCategory_description(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type TagCategory", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Query_findTagCategory_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Query_queryTagCategories(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Query_queryTagCategories, func(ctx context.Context) (any, error) { return ec.Resolvers.Query().QueryTagCategories(ctx) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal *QueryTagCategoriesResultType return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *QueryTagCategoriesResultType return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNQueryTagCategoriesResultType2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐQueryTagCategoriesResultType, true, true, ) } func (ec *executionContext) fieldContext_Query_queryTagCategories(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "count": return ec.fieldContext_QueryTagCategoriesResultType_count(ctx, field) case "tag_categories": return ec.fieldContext_QueryTagCategoriesResultType_tag_categories(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type QueryTagCategoriesResultType", field.Name) }, } return fc, nil } func (ec *executionContext) _Query_findScene(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Query_findScene, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Query().FindScene(ctx, fc.Args["id"].(uuid.UUID)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal *Scene return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *Scene return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalOScene2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐScene, true, false, ) } func (ec *executionContext) fieldContext_Query_findScene(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Scene_id(ctx, field) case "title": return ec.fieldContext_Scene_title(ctx, field) case "details": return ec.fieldContext_Scene_details(ctx, field) case "date": return ec.fieldContext_Scene_date(ctx, field) case "release_date": return ec.fieldContext_Scene_release_date(ctx, field) case "production_date": return ec.fieldContext_Scene_production_date(ctx, field) case "urls": return ec.fieldContext_Scene_urls(ctx, field) case "studio": return ec.fieldContext_Scene_studio(ctx, field) case "tags": return ec.fieldContext_Scene_tags(ctx, field) case "images": return ec.fieldContext_Scene_images(ctx, field) case "performers": return ec.fieldContext_Scene_performers(ctx, field) case "fingerprints": return ec.fieldContext_Scene_fingerprints(ctx, field) case "duration": return ec.fieldContext_Scene_duration(ctx, field) case "director": return ec.fieldContext_Scene_director(ctx, field) case "code": return ec.fieldContext_Scene_code(ctx, field) case "deleted": return ec.fieldContext_Scene_deleted(ctx, field) case "edits": return ec.fieldContext_Scene_edits(ctx, field) case "created": return ec.fieldContext_Scene_created(ctx, field) case "updated": return ec.fieldContext_Scene_updated(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Scene", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Query_findScene_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Query_findScenesBySceneFingerprints(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Query_findScenesBySceneFingerprints, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Query().FindScenesBySceneFingerprints(ctx, fc.Args["fingerprints"].([][]FingerprintQueryInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal [][]*Scene return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal [][]*Scene return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNScene2ᚕᚕᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneᚄ, true, true, ) } func (ec *executionContext) fieldContext_Query_findScenesBySceneFingerprints(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Scene_id(ctx, field) case "title": return ec.fieldContext_Scene_title(ctx, field) case "details": return ec.fieldContext_Scene_details(ctx, field) case "date": return ec.fieldContext_Scene_date(ctx, field) case "release_date": return ec.fieldContext_Scene_release_date(ctx, field) case "production_date": return ec.fieldContext_Scene_production_date(ctx, field) case "urls": return ec.fieldContext_Scene_urls(ctx, field) case "studio": return ec.fieldContext_Scene_studio(ctx, field) case "tags": return ec.fieldContext_Scene_tags(ctx, field) case "images": return ec.fieldContext_Scene_images(ctx, field) case "performers": return ec.fieldContext_Scene_performers(ctx, field) case "fingerprints": return ec.fieldContext_Scene_fingerprints(ctx, field) case "duration": return ec.fieldContext_Scene_duration(ctx, field) case "director": return ec.fieldContext_Scene_director(ctx, field) case "code": return ec.fieldContext_Scene_code(ctx, field) case "deleted": return ec.fieldContext_Scene_deleted(ctx, field) case "edits": return ec.fieldContext_Scene_edits(ctx, field) case "created": return ec.fieldContext_Scene_created(ctx, field) case "updated": return ec.fieldContext_Scene_updated(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Scene", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Query_findScenesBySceneFingerprints_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Query_queryScenes(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Query_queryScenes, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Query().QueryScenes(ctx, fc.Args["input"].(SceneQueryInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal *SceneQuery return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *SceneQuery return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNQueryScenesResultType2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneQuery, true, true, ) } func (ec *executionContext) fieldContext_Query_queryScenes(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "count": return ec.fieldContext_QueryScenesResultType_count(ctx, field) case "scenes": return ec.fieldContext_QueryScenesResultType_scenes(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type QueryScenesResultType", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Query_queryScenes_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Query_findSite(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Query_findSite, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Query().FindSite(ctx, fc.Args["id"].(uuid.UUID)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal *Site return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *Site return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalOSite2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSite, true, false, ) } func (ec *executionContext) fieldContext_Query_findSite(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Site_id(ctx, field) case "name": return ec.fieldContext_Site_name(ctx, field) case "description": return ec.fieldContext_Site_description(ctx, field) case "url": return ec.fieldContext_Site_url(ctx, field) case "regex": return ec.fieldContext_Site_regex(ctx, field) case "valid_types": return ec.fieldContext_Site_valid_types(ctx, field) case "icon": return ec.fieldContext_Site_icon(ctx, field) case "created": return ec.fieldContext_Site_created(ctx, field) case "updated": return ec.fieldContext_Site_updated(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Site", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Query_findSite_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Query_querySites(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Query_querySites, func(ctx context.Context) (any, error) { return ec.Resolvers.Query().QuerySites(ctx) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal *QuerySitesResultType return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *QuerySitesResultType return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNQuerySitesResultType2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐQuerySitesResultType, true, true, ) } func (ec *executionContext) fieldContext_Query_querySites(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "count": return ec.fieldContext_QuerySitesResultType_count(ctx, field) case "sites": return ec.fieldContext_QuerySitesResultType_sites(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type QuerySitesResultType", field.Name) }, } return fc, nil } func (ec *executionContext) _Query_findEdit(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Query_findEdit, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Query().FindEdit(ctx, fc.Args["id"].(uuid.UUID)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal *Edit return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *Edit return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalOEdit2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEdit, true, false, ) } func (ec *executionContext) fieldContext_Query_findEdit(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Edit_id(ctx, field) case "user": return ec.fieldContext_Edit_user(ctx, field) case "target": return ec.fieldContext_Edit_target(ctx, field) case "target_type": return ec.fieldContext_Edit_target_type(ctx, field) case "merge_sources": return ec.fieldContext_Edit_merge_sources(ctx, field) case "operation": return ec.fieldContext_Edit_operation(ctx, field) case "bot": return ec.fieldContext_Edit_bot(ctx, field) case "details": return ec.fieldContext_Edit_details(ctx, field) case "old_details": return ec.fieldContext_Edit_old_details(ctx, field) case "options": return ec.fieldContext_Edit_options(ctx, field) case "comments": return ec.fieldContext_Edit_comments(ctx, field) case "votes": return ec.fieldContext_Edit_votes(ctx, field) case "vote_count": return ec.fieldContext_Edit_vote_count(ctx, field) case "destructive": return ec.fieldContext_Edit_destructive(ctx, field) case "status": return ec.fieldContext_Edit_status(ctx, field) case "applied": return ec.fieldContext_Edit_applied(ctx, field) case "update_count": return ec.fieldContext_Edit_update_count(ctx, field) case "updatable": return ec.fieldContext_Edit_updatable(ctx, field) case "created": return ec.fieldContext_Edit_created(ctx, field) case "updated": return ec.fieldContext_Edit_updated(ctx, field) case "closed": return ec.fieldContext_Edit_closed(ctx, field) case "expires": return ec.fieldContext_Edit_expires(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Edit", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Query_findEdit_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Query_queryEdits(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Query_queryEdits, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Query().QueryEdits(ctx, fc.Args["input"].(EditQueryInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal *EditQuery return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *EditQuery return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNQueryEditsResultType2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditQuery, true, true, ) } func (ec *executionContext) fieldContext_Query_queryEdits(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "count": return ec.fieldContext_QueryEditsResultType_count(ctx, field) case "edits": return ec.fieldContext_QueryEditsResultType_edits(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type QueryEditsResultType", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Query_queryEdits_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Query_findUser(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Query_findUser, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Query().FindUser(ctx, fc.Args["id"].(*uuid.UUID), fc.Args["username"].(*string)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal *User return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *User return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalOUser2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUser, true, false, ) } func (ec *executionContext) fieldContext_Query_findUser(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_User_id(ctx, field) case "name": return ec.fieldContext_User_name(ctx, field) case "roles": return ec.fieldContext_User_roles(ctx, field) case "email": return ec.fieldContext_User_email(ctx, field) case "api_key": return ec.fieldContext_User_api_key(ctx, field) case "notification_subscriptions": return ec.fieldContext_User_notification_subscriptions(ctx, field) case "vote_count": return ec.fieldContext_User_vote_count(ctx, field) case "edit_count": return ec.fieldContext_User_edit_count(ctx, field) case "api_calls": return ec.fieldContext_User_api_calls(ctx, field) case "invited_by": return ec.fieldContext_User_invited_by(ctx, field) case "invite_tokens": return ec.fieldContext_User_invite_tokens(ctx, field) case "active_invite_codes": return ec.fieldContext_User_active_invite_codes(ctx, field) case "invite_codes": return ec.fieldContext_User_invite_codes(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type User", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Query_findUser_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Query_queryUsers(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Query_queryUsers, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Query().QueryUsers(ctx, fc.Args["input"].(UserQueryInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "ADMIN") if err != nil { var zeroVal *QueryUsersResultType return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *QueryUsersResultType return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNQueryUsersResultType2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐQueryUsersResultType, true, true, ) } func (ec *executionContext) fieldContext_Query_queryUsers(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "count": return ec.fieldContext_QueryUsersResultType_count(ctx, field) case "users": return ec.fieldContext_QueryUsersResultType_users(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type QueryUsersResultType", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Query_queryUsers_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Query_me(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Query_me, func(ctx context.Context) (any, error) { return ec.Resolvers.Query().Me(ctx) }, nil, ec.marshalOUser2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUser, true, false, ) } func (ec *executionContext) fieldContext_Query_me(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_User_id(ctx, field) case "name": return ec.fieldContext_User_name(ctx, field) case "roles": return ec.fieldContext_User_roles(ctx, field) case "email": return ec.fieldContext_User_email(ctx, field) case "api_key": return ec.fieldContext_User_api_key(ctx, field) case "notification_subscriptions": return ec.fieldContext_User_notification_subscriptions(ctx, field) case "vote_count": return ec.fieldContext_User_vote_count(ctx, field) case "edit_count": return ec.fieldContext_User_edit_count(ctx, field) case "api_calls": return ec.fieldContext_User_api_calls(ctx, field) case "invited_by": return ec.fieldContext_User_invited_by(ctx, field) case "invite_tokens": return ec.fieldContext_User_invite_tokens(ctx, field) case "active_invite_codes": return ec.fieldContext_User_active_invite_codes(ctx, field) case "invite_codes": return ec.fieldContext_User_invite_codes(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type User", field.Name) }, } return fc, nil } func (ec *executionContext) _Query_searchPerformer(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Query_searchPerformer, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Query().SearchPerformer(ctx, fc.Args["term"].(string), fc.Args["limit"].(*int)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal []Performer return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal []Performer return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNPerformer2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerᚄ, true, true, ) } func (ec *executionContext) fieldContext_Query_searchPerformer(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Performer_id(ctx, field) case "name": return ec.fieldContext_Performer_name(ctx, field) case "disambiguation": return ec.fieldContext_Performer_disambiguation(ctx, field) case "aliases": return ec.fieldContext_Performer_aliases(ctx, field) case "gender": return ec.fieldContext_Performer_gender(ctx, field) case "urls": return ec.fieldContext_Performer_urls(ctx, field) case "birthdate": return ec.fieldContext_Performer_birthdate(ctx, field) case "birth_date": return ec.fieldContext_Performer_birth_date(ctx, field) case "death_date": return ec.fieldContext_Performer_death_date(ctx, field) case "age": return ec.fieldContext_Performer_age(ctx, field) case "ethnicity": return ec.fieldContext_Performer_ethnicity(ctx, field) case "country": return ec.fieldContext_Performer_country(ctx, field) case "eye_color": return ec.fieldContext_Performer_eye_color(ctx, field) case "hair_color": return ec.fieldContext_Performer_hair_color(ctx, field) case "height": return ec.fieldContext_Performer_height(ctx, field) case "measurements": return ec.fieldContext_Performer_measurements(ctx, field) case "cup_size": return ec.fieldContext_Performer_cup_size(ctx, field) case "band_size": return ec.fieldContext_Performer_band_size(ctx, field) case "waist_size": return ec.fieldContext_Performer_waist_size(ctx, field) case "hip_size": return ec.fieldContext_Performer_hip_size(ctx, field) case "breast_type": return ec.fieldContext_Performer_breast_type(ctx, field) case "career_start_year": return ec.fieldContext_Performer_career_start_year(ctx, field) case "career_end_year": return ec.fieldContext_Performer_career_end_year(ctx, field) case "tattoos": return ec.fieldContext_Performer_tattoos(ctx, field) case "piercings": return ec.fieldContext_Performer_piercings(ctx, field) case "images": return ec.fieldContext_Performer_images(ctx, field) case "deleted": return ec.fieldContext_Performer_deleted(ctx, field) case "edits": return ec.fieldContext_Performer_edits(ctx, field) case "scene_count": return ec.fieldContext_Performer_scene_count(ctx, field) case "scenes": return ec.fieldContext_Performer_scenes(ctx, field) case "merged_ids": return ec.fieldContext_Performer_merged_ids(ctx, field) case "merged_into_id": return ec.fieldContext_Performer_merged_into_id(ctx, field) case "studios": return ec.fieldContext_Performer_studios(ctx, field) case "is_favorite": return ec.fieldContext_Performer_is_favorite(ctx, field) case "created": return ec.fieldContext_Performer_created(ctx, field) case "updated": return ec.fieldContext_Performer_updated(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Performer", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Query_searchPerformer_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Query_searchPerformers(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Query_searchPerformers, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Query().SearchPerformers(ctx, fc.Args["term"].(string), fc.Args["limit"].(*int), fc.Args["page"].(*int), fc.Args["per_page"].(*int), fc.Args["filter"].(*PerformerSearchFilter)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal *PerformerQuery return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *PerformerQuery return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNQueryPerformersResultType2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerQuery, true, true, ) } func (ec *executionContext) fieldContext_Query_searchPerformers(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "count": return ec.fieldContext_QueryPerformersResultType_count(ctx, field) case "performers": return ec.fieldContext_QueryPerformersResultType_performers(ctx, field) case "facets": return ec.fieldContext_QueryPerformersResultType_facets(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type QueryPerformersResultType", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Query_searchPerformers_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Query_searchScene(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Query_searchScene, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Query().SearchScene(ctx, fc.Args["term"].(string), fc.Args["limit"].(*int)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal []Scene return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal []Scene return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNScene2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneᚄ, true, true, ) } func (ec *executionContext) fieldContext_Query_searchScene(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Scene_id(ctx, field) case "title": return ec.fieldContext_Scene_title(ctx, field) case "details": return ec.fieldContext_Scene_details(ctx, field) case "date": return ec.fieldContext_Scene_date(ctx, field) case "release_date": return ec.fieldContext_Scene_release_date(ctx, field) case "production_date": return ec.fieldContext_Scene_production_date(ctx, field) case "urls": return ec.fieldContext_Scene_urls(ctx, field) case "studio": return ec.fieldContext_Scene_studio(ctx, field) case "tags": return ec.fieldContext_Scene_tags(ctx, field) case "images": return ec.fieldContext_Scene_images(ctx, field) case "performers": return ec.fieldContext_Scene_performers(ctx, field) case "fingerprints": return ec.fieldContext_Scene_fingerprints(ctx, field) case "duration": return ec.fieldContext_Scene_duration(ctx, field) case "director": return ec.fieldContext_Scene_director(ctx, field) case "code": return ec.fieldContext_Scene_code(ctx, field) case "deleted": return ec.fieldContext_Scene_deleted(ctx, field) case "edits": return ec.fieldContext_Scene_edits(ctx, field) case "created": return ec.fieldContext_Scene_created(ctx, field) case "updated": return ec.fieldContext_Scene_updated(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Scene", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Query_searchScene_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Query_searchScenes(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Query_searchScenes, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Query().SearchScenes(ctx, fc.Args["term"].(string), fc.Args["limit"].(*int), fc.Args["page"].(*int), fc.Args["per_page"].(*int)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal *SceneQuery return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *SceneQuery return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNQueryScenesResultType2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneQuery, true, true, ) } func (ec *executionContext) fieldContext_Query_searchScenes(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "count": return ec.fieldContext_QueryScenesResultType_count(ctx, field) case "scenes": return ec.fieldContext_QueryScenesResultType_scenes(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type QueryScenesResultType", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Query_searchScenes_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Query_searchTag(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Query_searchTag, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Query().SearchTag(ctx, fc.Args["term"].(string), fc.Args["limit"].(*int)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal []Tag return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal []Tag return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNTag2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagᚄ, true, true, ) } func (ec *executionContext) fieldContext_Query_searchTag(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Tag_id(ctx, field) case "name": return ec.fieldContext_Tag_name(ctx, field) case "description": return ec.fieldContext_Tag_description(ctx, field) case "aliases": return ec.fieldContext_Tag_aliases(ctx, field) case "deleted": return ec.fieldContext_Tag_deleted(ctx, field) case "edits": return ec.fieldContext_Tag_edits(ctx, field) case "category": return ec.fieldContext_Tag_category(ctx, field) case "created": return ec.fieldContext_Tag_created(ctx, field) case "updated": return ec.fieldContext_Tag_updated(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Tag", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Query_searchTag_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Query_searchStudio(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Query_searchStudio, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Query().SearchStudio(ctx, fc.Args["term"].(string), fc.Args["limit"].(*int)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal []Studio return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal []Studio return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNStudio2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStudioᚄ, true, true, ) } func (ec *executionContext) fieldContext_Query_searchStudio(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Studio_id(ctx, field) case "name": return ec.fieldContext_Studio_name(ctx, field) case "aliases": return ec.fieldContext_Studio_aliases(ctx, field) case "urls": return ec.fieldContext_Studio_urls(ctx, field) case "parent": return ec.fieldContext_Studio_parent(ctx, field) case "child_studios": return ec.fieldContext_Studio_child_studios(ctx, field) case "sub_studios": return ec.fieldContext_Studio_sub_studios(ctx, field) case "images": return ec.fieldContext_Studio_images(ctx, field) case "deleted": return ec.fieldContext_Studio_deleted(ctx, field) case "is_favorite": return ec.fieldContext_Studio_is_favorite(ctx, field) case "created": return ec.fieldContext_Studio_created(ctx, field) case "updated": return ec.fieldContext_Studio_updated(ctx, field) case "performers": return ec.fieldContext_Studio_performers(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Studio", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Query_searchStudio_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Query_findDraft(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Query_findDraft, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Query().FindDraft(ctx, fc.Args["id"].(uuid.UUID)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal *Draft return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *Draft return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalODraft2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDraft, true, false, ) } func (ec *executionContext) fieldContext_Query_findDraft(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Draft_id(ctx, field) case "created": return ec.fieldContext_Draft_created(ctx, field) case "expires": return ec.fieldContext_Draft_expires(ctx, field) case "data": return ec.fieldContext_Draft_data(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Draft", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Query_findDraft_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Query_findDrafts(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Query_findDrafts, func(ctx context.Context) (any, error) { return ec.Resolvers.Query().FindDrafts(ctx) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal []Draft return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal []Draft return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNDraft2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDraftᚄ, true, true, ) } func (ec *executionContext) fieldContext_Query_findDrafts(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Draft_id(ctx, field) case "created": return ec.fieldContext_Draft_created(ctx, field) case "expires": return ec.fieldContext_Draft_expires(ctx, field) case "data": return ec.fieldContext_Draft_data(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Draft", field.Name) }, } return fc, nil } func (ec *executionContext) _Query_queryExistingScene(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Query_queryExistingScene, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Query().QueryExistingScene(ctx, fc.Args["input"].(QueryExistingSceneInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal *QueryExistingSceneResult return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *QueryExistingSceneResult return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNQueryExistingSceneResult2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐQueryExistingSceneResult, true, true, ) } func (ec *executionContext) fieldContext_Query_queryExistingScene(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "edits": return ec.fieldContext_QueryExistingSceneResult_edits(ctx, field) case "scenes": return ec.fieldContext_QueryExistingSceneResult_scenes(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type QueryExistingSceneResult", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Query_queryExistingScene_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Query_queryExistingPerformer(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Query_queryExistingPerformer, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Query().QueryExistingPerformer(ctx, fc.Args["input"].(QueryExistingPerformerInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal *QueryExistingPerformerResult return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *QueryExistingPerformerResult return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNQueryExistingPerformerResult2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐQueryExistingPerformerResult, true, true, ) } func (ec *executionContext) fieldContext_Query_queryExistingPerformer(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "edits": return ec.fieldContext_QueryExistingPerformerResult_edits(ctx, field) case "performers": return ec.fieldContext_QueryExistingPerformerResult_performers(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type QueryExistingPerformerResult", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Query_queryExistingPerformer_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Query_version(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Query_version, func(ctx context.Context) (any, error) { return ec.Resolvers.Query().Version(ctx) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal *Version return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *Version return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNVersion2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐVersion, true, true, ) } func (ec *executionContext) fieldContext_Query_version(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "hash": return ec.fieldContext_Version_hash(ctx, field) case "build_time": return ec.fieldContext_Version_build_time(ctx, field) case "build_type": return ec.fieldContext_Version_build_type(ctx, field) case "version": return ec.fieldContext_Version_version(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Version", field.Name) }, } return fc, nil } func (ec *executionContext) _Query_getConfig(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Query_getConfig, func(ctx context.Context) (any, error) { return ec.Resolvers.Query().GetConfig(ctx) }, nil, ec.marshalNStashBoxConfig2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStashBoxConfig, true, true, ) } func (ec *executionContext) fieldContext_Query_getConfig(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "host_url": return ec.fieldContext_StashBoxConfig_host_url(ctx, field) case "require_invite": return ec.fieldContext_StashBoxConfig_require_invite(ctx, field) case "require_activation": return ec.fieldContext_StashBoxConfig_require_activation(ctx, field) case "vote_promotion_threshold": return ec.fieldContext_StashBoxConfig_vote_promotion_threshold(ctx, field) case "vote_application_threshold": return ec.fieldContext_StashBoxConfig_vote_application_threshold(ctx, field) case "voting_period": return ec.fieldContext_StashBoxConfig_voting_period(ctx, field) case "min_destructive_voting_period": return ec.fieldContext_StashBoxConfig_min_destructive_voting_period(ctx, field) case "vote_cron_interval": return ec.fieldContext_StashBoxConfig_vote_cron_interval(ctx, field) case "guidelines_url": return ec.fieldContext_StashBoxConfig_guidelines_url(ctx, field) case "require_scene_draft": return ec.fieldContext_StashBoxConfig_require_scene_draft(ctx, field) case "edit_update_limit": return ec.fieldContext_StashBoxConfig_edit_update_limit(ctx, field) case "require_tag_role": return ec.fieldContext_StashBoxConfig_require_tag_role(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type StashBoxConfig", field.Name) }, } return fc, nil } func (ec *executionContext) _Query_queryNotifications(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Query_queryNotifications, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Query().QueryNotifications(ctx, fc.Args["input"].(QueryNotificationsInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal *QueryNotificationsResult return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *QueryNotificationsResult return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNQueryNotificationsResult2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐQueryNotificationsResult, true, true, ) } func (ec *executionContext) fieldContext_Query_queryNotifications(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "count": return ec.fieldContext_QueryNotificationsResult_count(ctx, field) case "notifications": return ec.fieldContext_QueryNotificationsResult_notifications(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type QueryNotificationsResult", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Query_queryNotifications_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Query_getUnreadNotificationCount(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Query_getUnreadNotificationCount, func(ctx context.Context) (any, error) { return ec.Resolvers.Query().GetUnreadNotificationCount(ctx) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "READ") if err != nil { var zeroVal int return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal int return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_Query_getUnreadNotificationCount(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _Query_queryModAudits(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Query_queryModAudits, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Query().QueryModAudits(ctx, fc.Args["input"].(ModAuditQueryInput)) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { role, err := ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, "ADMIN") if err != nil { var zeroVal *ModAuditQuery return zeroVal, err } if ec.Directives.HasRole == nil { var zeroVal *ModAuditQuery return zeroVal, errors.New("directive hasRole is not implemented") } return ec.Directives.HasRole(ctx, nil, directive0, role) } next = directive1 return next }, ec.marshalNQueryModAuditsResultType2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐModAuditQuery, true, true, ) } func (ec *executionContext) fieldContext_Query_queryModAudits(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "count": return ec.fieldContext_QueryModAuditsResultType_count(ctx, field) case "audits": return ec.fieldContext_QueryModAuditsResultType_audits(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type QueryModAuditsResultType", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Query_queryModAudits_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Query___type(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Query___type, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.IntrospectType(fc.Args["name"].(string)) }, nil, ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType, true, false, ) } func (ec *executionContext) fieldContext_Query___type(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "kind": return ec.fieldContext___Type_kind(ctx, field) case "name": return ec.fieldContext___Type_name(ctx, field) case "description": return ec.fieldContext___Type_description(ctx, field) case "specifiedByURL": return ec.fieldContext___Type_specifiedByURL(ctx, field) case "fields": return ec.fieldContext___Type_fields(ctx, field) case "interfaces": return ec.fieldContext___Type_interfaces(ctx, field) case "possibleTypes": return ec.fieldContext___Type_possibleTypes(ctx, field) case "enumValues": return ec.fieldContext___Type_enumValues(ctx, field) case "inputFields": return ec.fieldContext___Type_inputFields(ctx, field) case "ofType": return ec.fieldContext___Type_ofType(ctx, field) case "isOneOf": return ec.fieldContext___Type_isOneOf(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Query___type_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Query___schema(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Query___schema, func(ctx context.Context) (any, error) { return ec.IntrospectSchema() }, nil, ec.marshalO__Schema2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐSchema, true, false, ) } func (ec *executionContext) fieldContext_Query___schema(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, IsMethod: true, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "description": return ec.fieldContext___Schema_description(ctx, field) case "types": return ec.fieldContext___Schema_types(ctx, field) case "queryType": return ec.fieldContext___Schema_queryType(ctx, field) case "mutationType": return ec.fieldContext___Schema_mutationType(ctx, field) case "subscriptionType": return ec.fieldContext___Schema_subscriptionType(ctx, field) case "directives": return ec.fieldContext___Schema_directives(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type __Schema", field.Name) }, } return fc, nil } func (ec *executionContext) _QueryEditsResultType_count(ctx context.Context, field graphql.CollectedField, obj *EditQuery) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_QueryEditsResultType_count, func(ctx context.Context) (any, error) { return ec.Resolvers.QueryEditsResultType().Count(ctx, obj) }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_QueryEditsResultType_count(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "QueryEditsResultType", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _QueryEditsResultType_edits(ctx context.Context, field graphql.CollectedField, obj *EditQuery) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_QueryEditsResultType_edits, func(ctx context.Context) (any, error) { return ec.Resolvers.QueryEditsResultType().Edits(ctx, obj) }, nil, ec.marshalNEdit2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditᚄ, true, true, ) } func (ec *executionContext) fieldContext_QueryEditsResultType_edits(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "QueryEditsResultType", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Edit_id(ctx, field) case "user": return ec.fieldContext_Edit_user(ctx, field) case "target": return ec.fieldContext_Edit_target(ctx, field) case "target_type": return ec.fieldContext_Edit_target_type(ctx, field) case "merge_sources": return ec.fieldContext_Edit_merge_sources(ctx, field) case "operation": return ec.fieldContext_Edit_operation(ctx, field) case "bot": return ec.fieldContext_Edit_bot(ctx, field) case "details": return ec.fieldContext_Edit_details(ctx, field) case "old_details": return ec.fieldContext_Edit_old_details(ctx, field) case "options": return ec.fieldContext_Edit_options(ctx, field) case "comments": return ec.fieldContext_Edit_comments(ctx, field) case "votes": return ec.fieldContext_Edit_votes(ctx, field) case "vote_count": return ec.fieldContext_Edit_vote_count(ctx, field) case "destructive": return ec.fieldContext_Edit_destructive(ctx, field) case "status": return ec.fieldContext_Edit_status(ctx, field) case "applied": return ec.fieldContext_Edit_applied(ctx, field) case "update_count": return ec.fieldContext_Edit_update_count(ctx, field) case "updatable": return ec.fieldContext_Edit_updatable(ctx, field) case "created": return ec.fieldContext_Edit_created(ctx, field) case "updated": return ec.fieldContext_Edit_updated(ctx, field) case "closed": return ec.fieldContext_Edit_closed(ctx, field) case "expires": return ec.fieldContext_Edit_expires(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Edit", field.Name) }, } return fc, nil } func (ec *executionContext) _QueryExistingPerformerResult_edits(ctx context.Context, field graphql.CollectedField, obj *QueryExistingPerformerResult) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_QueryExistingPerformerResult_edits, func(ctx context.Context) (any, error) { return ec.Resolvers.QueryExistingPerformerResult().Edits(ctx, obj) }, nil, ec.marshalNEdit2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditᚄ, true, true, ) } func (ec *executionContext) fieldContext_QueryExistingPerformerResult_edits(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "QueryExistingPerformerResult", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Edit_id(ctx, field) case "user": return ec.fieldContext_Edit_user(ctx, field) case "target": return ec.fieldContext_Edit_target(ctx, field) case "target_type": return ec.fieldContext_Edit_target_type(ctx, field) case "merge_sources": return ec.fieldContext_Edit_merge_sources(ctx, field) case "operation": return ec.fieldContext_Edit_operation(ctx, field) case "bot": return ec.fieldContext_Edit_bot(ctx, field) case "details": return ec.fieldContext_Edit_details(ctx, field) case "old_details": return ec.fieldContext_Edit_old_details(ctx, field) case "options": return ec.fieldContext_Edit_options(ctx, field) case "comments": return ec.fieldContext_Edit_comments(ctx, field) case "votes": return ec.fieldContext_Edit_votes(ctx, field) case "vote_count": return ec.fieldContext_Edit_vote_count(ctx, field) case "destructive": return ec.fieldContext_Edit_destructive(ctx, field) case "status": return ec.fieldContext_Edit_status(ctx, field) case "applied": return ec.fieldContext_Edit_applied(ctx, field) case "update_count": return ec.fieldContext_Edit_update_count(ctx, field) case "updatable": return ec.fieldContext_Edit_updatable(ctx, field) case "created": return ec.fieldContext_Edit_created(ctx, field) case "updated": return ec.fieldContext_Edit_updated(ctx, field) case "closed": return ec.fieldContext_Edit_closed(ctx, field) case "expires": return ec.fieldContext_Edit_expires(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Edit", field.Name) }, } return fc, nil } func (ec *executionContext) _QueryExistingPerformerResult_performers(ctx context.Context, field graphql.CollectedField, obj *QueryExistingPerformerResult) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_QueryExistingPerformerResult_performers, func(ctx context.Context) (any, error) { return ec.Resolvers.QueryExistingPerformerResult().Performers(ctx, obj) }, nil, ec.marshalNPerformer2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerᚄ, true, true, ) } func (ec *executionContext) fieldContext_QueryExistingPerformerResult_performers(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "QueryExistingPerformerResult", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Performer_id(ctx, field) case "name": return ec.fieldContext_Performer_name(ctx, field) case "disambiguation": return ec.fieldContext_Performer_disambiguation(ctx, field) case "aliases": return ec.fieldContext_Performer_aliases(ctx, field) case "gender": return ec.fieldContext_Performer_gender(ctx, field) case "urls": return ec.fieldContext_Performer_urls(ctx, field) case "birthdate": return ec.fieldContext_Performer_birthdate(ctx, field) case "birth_date": return ec.fieldContext_Performer_birth_date(ctx, field) case "death_date": return ec.fieldContext_Performer_death_date(ctx, field) case "age": return ec.fieldContext_Performer_age(ctx, field) case "ethnicity": return ec.fieldContext_Performer_ethnicity(ctx, field) case "country": return ec.fieldContext_Performer_country(ctx, field) case "eye_color": return ec.fieldContext_Performer_eye_color(ctx, field) case "hair_color": return ec.fieldContext_Performer_hair_color(ctx, field) case "height": return ec.fieldContext_Performer_height(ctx, field) case "measurements": return ec.fieldContext_Performer_measurements(ctx, field) case "cup_size": return ec.fieldContext_Performer_cup_size(ctx, field) case "band_size": return ec.fieldContext_Performer_band_size(ctx, field) case "waist_size": return ec.fieldContext_Performer_waist_size(ctx, field) case "hip_size": return ec.fieldContext_Performer_hip_size(ctx, field) case "breast_type": return ec.fieldContext_Performer_breast_type(ctx, field) case "career_start_year": return ec.fieldContext_Performer_career_start_year(ctx, field) case "career_end_year": return ec.fieldContext_Performer_career_end_year(ctx, field) case "tattoos": return ec.fieldContext_Performer_tattoos(ctx, field) case "piercings": return ec.fieldContext_Performer_piercings(ctx, field) case "images": return ec.fieldContext_Performer_images(ctx, field) case "deleted": return ec.fieldContext_Performer_deleted(ctx, field) case "edits": return ec.fieldContext_Performer_edits(ctx, field) case "scene_count": return ec.fieldContext_Performer_scene_count(ctx, field) case "scenes": return ec.fieldContext_Performer_scenes(ctx, field) case "merged_ids": return ec.fieldContext_Performer_merged_ids(ctx, field) case "merged_into_id": return ec.fieldContext_Performer_merged_into_id(ctx, field) case "studios": return ec.fieldContext_Performer_studios(ctx, field) case "is_favorite": return ec.fieldContext_Performer_is_favorite(ctx, field) case "created": return ec.fieldContext_Performer_created(ctx, field) case "updated": return ec.fieldContext_Performer_updated(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Performer", field.Name) }, } return fc, nil } func (ec *executionContext) _QueryExistingSceneResult_edits(ctx context.Context, field graphql.CollectedField, obj *QueryExistingSceneResult) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_QueryExistingSceneResult_edits, func(ctx context.Context) (any, error) { return ec.Resolvers.QueryExistingSceneResult().Edits(ctx, obj) }, nil, ec.marshalNEdit2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditᚄ, true, true, ) } func (ec *executionContext) fieldContext_QueryExistingSceneResult_edits(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "QueryExistingSceneResult", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Edit_id(ctx, field) case "user": return ec.fieldContext_Edit_user(ctx, field) case "target": return ec.fieldContext_Edit_target(ctx, field) case "target_type": return ec.fieldContext_Edit_target_type(ctx, field) case "merge_sources": return ec.fieldContext_Edit_merge_sources(ctx, field) case "operation": return ec.fieldContext_Edit_operation(ctx, field) case "bot": return ec.fieldContext_Edit_bot(ctx, field) case "details": return ec.fieldContext_Edit_details(ctx, field) case "old_details": return ec.fieldContext_Edit_old_details(ctx, field) case "options": return ec.fieldContext_Edit_options(ctx, field) case "comments": return ec.fieldContext_Edit_comments(ctx, field) case "votes": return ec.fieldContext_Edit_votes(ctx, field) case "vote_count": return ec.fieldContext_Edit_vote_count(ctx, field) case "destructive": return ec.fieldContext_Edit_destructive(ctx, field) case "status": return ec.fieldContext_Edit_status(ctx, field) case "applied": return ec.fieldContext_Edit_applied(ctx, field) case "update_count": return ec.fieldContext_Edit_update_count(ctx, field) case "updatable": return ec.fieldContext_Edit_updatable(ctx, field) case "created": return ec.fieldContext_Edit_created(ctx, field) case "updated": return ec.fieldContext_Edit_updated(ctx, field) case "closed": return ec.fieldContext_Edit_closed(ctx, field) case "expires": return ec.fieldContext_Edit_expires(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Edit", field.Name) }, } return fc, nil } func (ec *executionContext) _QueryExistingSceneResult_scenes(ctx context.Context, field graphql.CollectedField, obj *QueryExistingSceneResult) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_QueryExistingSceneResult_scenes, func(ctx context.Context) (any, error) { return ec.Resolvers.QueryExistingSceneResult().Scenes(ctx, obj) }, nil, ec.marshalNScene2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneᚄ, true, true, ) } func (ec *executionContext) fieldContext_QueryExistingSceneResult_scenes(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "QueryExistingSceneResult", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Scene_id(ctx, field) case "title": return ec.fieldContext_Scene_title(ctx, field) case "details": return ec.fieldContext_Scene_details(ctx, field) case "date": return ec.fieldContext_Scene_date(ctx, field) case "release_date": return ec.fieldContext_Scene_release_date(ctx, field) case "production_date": return ec.fieldContext_Scene_production_date(ctx, field) case "urls": return ec.fieldContext_Scene_urls(ctx, field) case "studio": return ec.fieldContext_Scene_studio(ctx, field) case "tags": return ec.fieldContext_Scene_tags(ctx, field) case "images": return ec.fieldContext_Scene_images(ctx, field) case "performers": return ec.fieldContext_Scene_performers(ctx, field) case "fingerprints": return ec.fieldContext_Scene_fingerprints(ctx, field) case "duration": return ec.fieldContext_Scene_duration(ctx, field) case "director": return ec.fieldContext_Scene_director(ctx, field) case "code": return ec.fieldContext_Scene_code(ctx, field) case "deleted": return ec.fieldContext_Scene_deleted(ctx, field) case "edits": return ec.fieldContext_Scene_edits(ctx, field) case "created": return ec.fieldContext_Scene_created(ctx, field) case "updated": return ec.fieldContext_Scene_updated(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Scene", field.Name) }, } return fc, nil } func (ec *executionContext) _QueryModAuditsResultType_count(ctx context.Context, field graphql.CollectedField, obj *ModAuditQuery) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_QueryModAuditsResultType_count, func(ctx context.Context) (any, error) { return ec.Resolvers.QueryModAuditsResultType().Count(ctx, obj) }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_QueryModAuditsResultType_count(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "QueryModAuditsResultType", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _QueryModAuditsResultType_audits(ctx context.Context, field graphql.CollectedField, obj *ModAuditQuery) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_QueryModAuditsResultType_audits, func(ctx context.Context) (any, error) { return ec.Resolvers.QueryModAuditsResultType().Audits(ctx, obj) }, nil, ec.marshalNModAudit2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐModAuditᚄ, true, true, ) } func (ec *executionContext) fieldContext_QueryModAuditsResultType_audits(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "QueryModAuditsResultType", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_ModAudit_id(ctx, field) case "action": return ec.fieldContext_ModAudit_action(ctx, field) case "user": return ec.fieldContext_ModAudit_user(ctx, field) case "target_id": return ec.fieldContext_ModAudit_target_id(ctx, field) case "target_type": return ec.fieldContext_ModAudit_target_type(ctx, field) case "data": return ec.fieldContext_ModAudit_data(ctx, field) case "reason": return ec.fieldContext_ModAudit_reason(ctx, field) case "created_at": return ec.fieldContext_ModAudit_created_at(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type ModAudit", field.Name) }, } return fc, nil } func (ec *executionContext) _QueryNotificationsResult_count(ctx context.Context, field graphql.CollectedField, obj *QueryNotificationsResult) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_QueryNotificationsResult_count, func(ctx context.Context) (any, error) { return ec.Resolvers.QueryNotificationsResult().Count(ctx, obj) }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_QueryNotificationsResult_count(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "QueryNotificationsResult", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _QueryNotificationsResult_notifications(ctx context.Context, field graphql.CollectedField, obj *QueryNotificationsResult) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_QueryNotificationsResult_notifications, func(ctx context.Context) (any, error) { return ec.Resolvers.QueryNotificationsResult().Notifications(ctx, obj) }, nil, ec.marshalNNotification2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐNotificationᚄ, true, true, ) } func (ec *executionContext) fieldContext_QueryNotificationsResult_notifications(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "QueryNotificationsResult", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "created": return ec.fieldContext_Notification_created(ctx, field) case "read": return ec.fieldContext_Notification_read(ctx, field) case "data": return ec.fieldContext_Notification_data(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Notification", field.Name) }, } return fc, nil } func (ec *executionContext) _QueryPerformersResultType_count(ctx context.Context, field graphql.CollectedField, obj *PerformerQuery) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_QueryPerformersResultType_count, func(ctx context.Context) (any, error) { return ec.Resolvers.QueryPerformersResultType().Count(ctx, obj) }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_QueryPerformersResultType_count(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "QueryPerformersResultType", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _QueryPerformersResultType_performers(ctx context.Context, field graphql.CollectedField, obj *PerformerQuery) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_QueryPerformersResultType_performers, func(ctx context.Context) (any, error) { return ec.Resolvers.QueryPerformersResultType().Performers(ctx, obj) }, nil, ec.marshalNPerformer2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerᚄ, true, true, ) } func (ec *executionContext) fieldContext_QueryPerformersResultType_performers(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "QueryPerformersResultType", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Performer_id(ctx, field) case "name": return ec.fieldContext_Performer_name(ctx, field) case "disambiguation": return ec.fieldContext_Performer_disambiguation(ctx, field) case "aliases": return ec.fieldContext_Performer_aliases(ctx, field) case "gender": return ec.fieldContext_Performer_gender(ctx, field) case "urls": return ec.fieldContext_Performer_urls(ctx, field) case "birthdate": return ec.fieldContext_Performer_birthdate(ctx, field) case "birth_date": return ec.fieldContext_Performer_birth_date(ctx, field) case "death_date": return ec.fieldContext_Performer_death_date(ctx, field) case "age": return ec.fieldContext_Performer_age(ctx, field) case "ethnicity": return ec.fieldContext_Performer_ethnicity(ctx, field) case "country": return ec.fieldContext_Performer_country(ctx, field) case "eye_color": return ec.fieldContext_Performer_eye_color(ctx, field) case "hair_color": return ec.fieldContext_Performer_hair_color(ctx, field) case "height": return ec.fieldContext_Performer_height(ctx, field) case "measurements": return ec.fieldContext_Performer_measurements(ctx, field) case "cup_size": return ec.fieldContext_Performer_cup_size(ctx, field) case "band_size": return ec.fieldContext_Performer_band_size(ctx, field) case "waist_size": return ec.fieldContext_Performer_waist_size(ctx, field) case "hip_size": return ec.fieldContext_Performer_hip_size(ctx, field) case "breast_type": return ec.fieldContext_Performer_breast_type(ctx, field) case "career_start_year": return ec.fieldContext_Performer_career_start_year(ctx, field) case "career_end_year": return ec.fieldContext_Performer_career_end_year(ctx, field) case "tattoos": return ec.fieldContext_Performer_tattoos(ctx, field) case "piercings": return ec.fieldContext_Performer_piercings(ctx, field) case "images": return ec.fieldContext_Performer_images(ctx, field) case "deleted": return ec.fieldContext_Performer_deleted(ctx, field) case "edits": return ec.fieldContext_Performer_edits(ctx, field) case "scene_count": return ec.fieldContext_Performer_scene_count(ctx, field) case "scenes": return ec.fieldContext_Performer_scenes(ctx, field) case "merged_ids": return ec.fieldContext_Performer_merged_ids(ctx, field) case "merged_into_id": return ec.fieldContext_Performer_merged_into_id(ctx, field) case "studios": return ec.fieldContext_Performer_studios(ctx, field) case "is_favorite": return ec.fieldContext_Performer_is_favorite(ctx, field) case "created": return ec.fieldContext_Performer_created(ctx, field) case "updated": return ec.fieldContext_Performer_updated(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Performer", field.Name) }, } return fc, nil } func (ec *executionContext) _QueryPerformersResultType_facets(ctx context.Context, field graphql.CollectedField, obj *PerformerQuery) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_QueryPerformersResultType_facets, func(ctx context.Context) (any, error) { return ec.Resolvers.QueryPerformersResultType().Facets(ctx, obj) }, nil, ec.marshalOPerformerSearchFacets2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerSearchFacets, true, false, ) } func (ec *executionContext) fieldContext_QueryPerformersResultType_facets(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "QueryPerformersResultType", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "genders": return ec.fieldContext_PerformerSearchFacets_genders(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type PerformerSearchFacets", field.Name) }, } return fc, nil } func (ec *executionContext) _QueryScenesResultType_count(ctx context.Context, field graphql.CollectedField, obj *SceneQuery) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_QueryScenesResultType_count, func(ctx context.Context) (any, error) { return ec.Resolvers.QueryScenesResultType().Count(ctx, obj) }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_QueryScenesResultType_count(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "QueryScenesResultType", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _QueryScenesResultType_scenes(ctx context.Context, field graphql.CollectedField, obj *SceneQuery) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_QueryScenesResultType_scenes, func(ctx context.Context) (any, error) { return ec.Resolvers.QueryScenesResultType().Scenes(ctx, obj) }, nil, ec.marshalNScene2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneᚄ, true, true, ) } func (ec *executionContext) fieldContext_QueryScenesResultType_scenes(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "QueryScenesResultType", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Scene_id(ctx, field) case "title": return ec.fieldContext_Scene_title(ctx, field) case "details": return ec.fieldContext_Scene_details(ctx, field) case "date": return ec.fieldContext_Scene_date(ctx, field) case "release_date": return ec.fieldContext_Scene_release_date(ctx, field) case "production_date": return ec.fieldContext_Scene_production_date(ctx, field) case "urls": return ec.fieldContext_Scene_urls(ctx, field) case "studio": return ec.fieldContext_Scene_studio(ctx, field) case "tags": return ec.fieldContext_Scene_tags(ctx, field) case "images": return ec.fieldContext_Scene_images(ctx, field) case "performers": return ec.fieldContext_Scene_performers(ctx, field) case "fingerprints": return ec.fieldContext_Scene_fingerprints(ctx, field) case "duration": return ec.fieldContext_Scene_duration(ctx, field) case "director": return ec.fieldContext_Scene_director(ctx, field) case "code": return ec.fieldContext_Scene_code(ctx, field) case "deleted": return ec.fieldContext_Scene_deleted(ctx, field) case "edits": return ec.fieldContext_Scene_edits(ctx, field) case "created": return ec.fieldContext_Scene_created(ctx, field) case "updated": return ec.fieldContext_Scene_updated(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Scene", field.Name) }, } return fc, nil } func (ec *executionContext) _QuerySitesResultType_count(ctx context.Context, field graphql.CollectedField, obj *QuerySitesResultType) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_QuerySitesResultType_count, func(ctx context.Context) (any, error) { return obj.Count, nil }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_QuerySitesResultType_count(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "QuerySitesResultType", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _QuerySitesResultType_sites(ctx context.Context, field graphql.CollectedField, obj *QuerySitesResultType) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_QuerySitesResultType_sites, func(ctx context.Context) (any, error) { return obj.Sites, nil }, nil, ec.marshalNSite2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSiteᚄ, true, true, ) } func (ec *executionContext) fieldContext_QuerySitesResultType_sites(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "QuerySitesResultType", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Site_id(ctx, field) case "name": return ec.fieldContext_Site_name(ctx, field) case "description": return ec.fieldContext_Site_description(ctx, field) case "url": return ec.fieldContext_Site_url(ctx, field) case "regex": return ec.fieldContext_Site_regex(ctx, field) case "valid_types": return ec.fieldContext_Site_valid_types(ctx, field) case "icon": return ec.fieldContext_Site_icon(ctx, field) case "created": return ec.fieldContext_Site_created(ctx, field) case "updated": return ec.fieldContext_Site_updated(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Site", field.Name) }, } return fc, nil } func (ec *executionContext) _QueryStudiosResultType_count(ctx context.Context, field graphql.CollectedField, obj *QueryStudiosResultType) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_QueryStudiosResultType_count, func(ctx context.Context) (any, error) { return obj.Count, nil }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_QueryStudiosResultType_count(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "QueryStudiosResultType", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _QueryStudiosResultType_studios(ctx context.Context, field graphql.CollectedField, obj *QueryStudiosResultType) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_QueryStudiosResultType_studios, func(ctx context.Context) (any, error) { return obj.Studios, nil }, nil, ec.marshalNStudio2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStudioᚄ, true, true, ) } func (ec *executionContext) fieldContext_QueryStudiosResultType_studios(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "QueryStudiosResultType", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Studio_id(ctx, field) case "name": return ec.fieldContext_Studio_name(ctx, field) case "aliases": return ec.fieldContext_Studio_aliases(ctx, field) case "urls": return ec.fieldContext_Studio_urls(ctx, field) case "parent": return ec.fieldContext_Studio_parent(ctx, field) case "child_studios": return ec.fieldContext_Studio_child_studios(ctx, field) case "sub_studios": return ec.fieldContext_Studio_sub_studios(ctx, field) case "images": return ec.fieldContext_Studio_images(ctx, field) case "deleted": return ec.fieldContext_Studio_deleted(ctx, field) case "is_favorite": return ec.fieldContext_Studio_is_favorite(ctx, field) case "created": return ec.fieldContext_Studio_created(ctx, field) case "updated": return ec.fieldContext_Studio_updated(ctx, field) case "performers": return ec.fieldContext_Studio_performers(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Studio", field.Name) }, } return fc, nil } func (ec *executionContext) _QueryTagCategoriesResultType_count(ctx context.Context, field graphql.CollectedField, obj *QueryTagCategoriesResultType) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_QueryTagCategoriesResultType_count, func(ctx context.Context) (any, error) { return obj.Count, nil }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_QueryTagCategoriesResultType_count(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "QueryTagCategoriesResultType", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _QueryTagCategoriesResultType_tag_categories(ctx context.Context, field graphql.CollectedField, obj *QueryTagCategoriesResultType) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_QueryTagCategoriesResultType_tag_categories, func(ctx context.Context) (any, error) { return obj.TagCategories, nil }, nil, ec.marshalNTagCategory2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagCategoryᚄ, true, true, ) } func (ec *executionContext) fieldContext_QueryTagCategoriesResultType_tag_categories(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "QueryTagCategoriesResultType", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_TagCategory_id(ctx, field) case "name": return ec.fieldContext_TagCategory_name(ctx, field) case "group": return ec.fieldContext_TagCategory_group(ctx, field) case "description": return ec.fieldContext_TagCategory_description(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type TagCategory", field.Name) }, } return fc, nil } func (ec *executionContext) _QueryTagsResultType_count(ctx context.Context, field graphql.CollectedField, obj *QueryTagsResultType) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_QueryTagsResultType_count, func(ctx context.Context) (any, error) { return obj.Count, nil }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_QueryTagsResultType_count(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "QueryTagsResultType", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _QueryTagsResultType_tags(ctx context.Context, field graphql.CollectedField, obj *QueryTagsResultType) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_QueryTagsResultType_tags, func(ctx context.Context) (any, error) { return obj.Tags, nil }, nil, ec.marshalNTag2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagᚄ, true, true, ) } func (ec *executionContext) fieldContext_QueryTagsResultType_tags(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "QueryTagsResultType", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Tag_id(ctx, field) case "name": return ec.fieldContext_Tag_name(ctx, field) case "description": return ec.fieldContext_Tag_description(ctx, field) case "aliases": return ec.fieldContext_Tag_aliases(ctx, field) case "deleted": return ec.fieldContext_Tag_deleted(ctx, field) case "edits": return ec.fieldContext_Tag_edits(ctx, field) case "category": return ec.fieldContext_Tag_category(ctx, field) case "created": return ec.fieldContext_Tag_created(ctx, field) case "updated": return ec.fieldContext_Tag_updated(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Tag", field.Name) }, } return fc, nil } func (ec *executionContext) _QueryUsersResultType_count(ctx context.Context, field graphql.CollectedField, obj *QueryUsersResultType) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_QueryUsersResultType_count, func(ctx context.Context) (any, error) { return obj.Count, nil }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_QueryUsersResultType_count(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "QueryUsersResultType", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _QueryUsersResultType_users(ctx context.Context, field graphql.CollectedField, obj *QueryUsersResultType) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_QueryUsersResultType_users, func(ctx context.Context) (any, error) { return obj.Users, nil }, nil, ec.marshalNUser2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUserᚄ, true, true, ) } func (ec *executionContext) fieldContext_QueryUsersResultType_users(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "QueryUsersResultType", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_User_id(ctx, field) case "name": return ec.fieldContext_User_name(ctx, field) case "roles": return ec.fieldContext_User_roles(ctx, field) case "email": return ec.fieldContext_User_email(ctx, field) case "api_key": return ec.fieldContext_User_api_key(ctx, field) case "notification_subscriptions": return ec.fieldContext_User_notification_subscriptions(ctx, field) case "vote_count": return ec.fieldContext_User_vote_count(ctx, field) case "edit_count": return ec.fieldContext_User_edit_count(ctx, field) case "api_calls": return ec.fieldContext_User_api_calls(ctx, field) case "invited_by": return ec.fieldContext_User_invited_by(ctx, field) case "invite_tokens": return ec.fieldContext_User_invite_tokens(ctx, field) case "active_invite_codes": return ec.fieldContext_User_active_invite_codes(ctx, field) case "invite_codes": return ec.fieldContext_User_invite_codes(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type User", field.Name) }, } return fc, nil } func (ec *executionContext) _Scene_id(ctx context.Context, field graphql.CollectedField, obj *Scene) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Scene_id, func(ctx context.Context) (any, error) { return obj.ID, nil }, nil, ec.marshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID, true, true, ) } func (ec *executionContext) fieldContext_Scene_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Scene", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type ID does not have child fields") }, } return fc, nil } func (ec *executionContext) _Scene_title(ctx context.Context, field graphql.CollectedField, obj *Scene) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Scene_title, func(ctx context.Context) (any, error) { return obj.Title, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_Scene_title(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Scene", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _Scene_details(ctx context.Context, field graphql.CollectedField, obj *Scene) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Scene_details, func(ctx context.Context) (any, error) { return obj.Details, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_Scene_details(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Scene", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _Scene_date(ctx context.Context, field graphql.CollectedField, obj *Scene) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Scene_date, func(ctx context.Context) (any, error) { return obj.Date, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_Scene_date(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Scene", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _Scene_release_date(ctx context.Context, field graphql.CollectedField, obj *Scene) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Scene_release_date, func(ctx context.Context) (any, error) { return ec.Resolvers.Scene().ReleaseDate(ctx, obj) }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_Scene_release_date(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Scene", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _Scene_production_date(ctx context.Context, field graphql.CollectedField, obj *Scene) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Scene_production_date, func(ctx context.Context) (any, error) { return obj.ProductionDate, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_Scene_production_date(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Scene", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _Scene_urls(ctx context.Context, field graphql.CollectedField, obj *Scene) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Scene_urls, func(ctx context.Context) (any, error) { return ec.Resolvers.Scene().Urls(ctx, obj) }, nil, ec.marshalNURL2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐURLᚄ, true, true, ) } func (ec *executionContext) fieldContext_Scene_urls(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Scene", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "url": return ec.fieldContext_URL_url(ctx, field) case "type": return ec.fieldContext_URL_type(ctx, field) case "site": return ec.fieldContext_URL_site(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type URL", field.Name) }, } return fc, nil } func (ec *executionContext) _Scene_studio(ctx context.Context, field graphql.CollectedField, obj *Scene) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Scene_studio, func(ctx context.Context) (any, error) { return ec.Resolvers.Scene().Studio(ctx, obj) }, nil, ec.marshalOStudio2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStudio, true, false, ) } func (ec *executionContext) fieldContext_Scene_studio(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Scene", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Studio_id(ctx, field) case "name": return ec.fieldContext_Studio_name(ctx, field) case "aliases": return ec.fieldContext_Studio_aliases(ctx, field) case "urls": return ec.fieldContext_Studio_urls(ctx, field) case "parent": return ec.fieldContext_Studio_parent(ctx, field) case "child_studios": return ec.fieldContext_Studio_child_studios(ctx, field) case "sub_studios": return ec.fieldContext_Studio_sub_studios(ctx, field) case "images": return ec.fieldContext_Studio_images(ctx, field) case "deleted": return ec.fieldContext_Studio_deleted(ctx, field) case "is_favorite": return ec.fieldContext_Studio_is_favorite(ctx, field) case "created": return ec.fieldContext_Studio_created(ctx, field) case "updated": return ec.fieldContext_Studio_updated(ctx, field) case "performers": return ec.fieldContext_Studio_performers(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Studio", field.Name) }, } return fc, nil } func (ec *executionContext) _Scene_tags(ctx context.Context, field graphql.CollectedField, obj *Scene) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Scene_tags, func(ctx context.Context) (any, error) { return ec.Resolvers.Scene().Tags(ctx, obj) }, nil, ec.marshalNTag2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagᚄ, true, true, ) } func (ec *executionContext) fieldContext_Scene_tags(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Scene", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Tag_id(ctx, field) case "name": return ec.fieldContext_Tag_name(ctx, field) case "description": return ec.fieldContext_Tag_description(ctx, field) case "aliases": return ec.fieldContext_Tag_aliases(ctx, field) case "deleted": return ec.fieldContext_Tag_deleted(ctx, field) case "edits": return ec.fieldContext_Tag_edits(ctx, field) case "category": return ec.fieldContext_Tag_category(ctx, field) case "created": return ec.fieldContext_Tag_created(ctx, field) case "updated": return ec.fieldContext_Tag_updated(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Tag", field.Name) }, } return fc, nil } func (ec *executionContext) _Scene_images(ctx context.Context, field graphql.CollectedField, obj *Scene) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Scene_images, func(ctx context.Context) (any, error) { return ec.Resolvers.Scene().Images(ctx, obj) }, nil, ec.marshalNImage2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐImageᚄ, true, true, ) } func (ec *executionContext) fieldContext_Scene_images(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Scene", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Image_id(ctx, field) case "url": return ec.fieldContext_Image_url(ctx, field) case "width": return ec.fieldContext_Image_width(ctx, field) case "height": return ec.fieldContext_Image_height(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Image", field.Name) }, } return fc, nil } func (ec *executionContext) _Scene_performers(ctx context.Context, field graphql.CollectedField, obj *Scene) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Scene_performers, func(ctx context.Context) (any, error) { return ec.Resolvers.Scene().Performers(ctx, obj) }, nil, ec.marshalNPerformerAppearance2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerAppearanceᚄ, true, true, ) } func (ec *executionContext) fieldContext_Scene_performers(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Scene", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "performer": return ec.fieldContext_PerformerAppearance_performer(ctx, field) case "as": return ec.fieldContext_PerformerAppearance_as(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type PerformerAppearance", field.Name) }, } return fc, nil } func (ec *executionContext) _Scene_fingerprints(ctx context.Context, field graphql.CollectedField, obj *Scene) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Scene_fingerprints, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Scene().Fingerprints(ctx, obj, fc.Args["is_submitted"].(*bool)) }, nil, ec.marshalNFingerprint2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintᚄ, true, true, ) } func (ec *executionContext) fieldContext_Scene_fingerprints(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Scene", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "hash": return ec.fieldContext_Fingerprint_hash(ctx, field) case "algorithm": return ec.fieldContext_Fingerprint_algorithm(ctx, field) case "duration": return ec.fieldContext_Fingerprint_duration(ctx, field) case "submissions": return ec.fieldContext_Fingerprint_submissions(ctx, field) case "reports": return ec.fieldContext_Fingerprint_reports(ctx, field) case "created": return ec.fieldContext_Fingerprint_created(ctx, field) case "updated": return ec.fieldContext_Fingerprint_updated(ctx, field) case "user_submitted": return ec.fieldContext_Fingerprint_user_submitted(ctx, field) case "user_reported": return ec.fieldContext_Fingerprint_user_reported(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Fingerprint", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Scene_fingerprints_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Scene_duration(ctx context.Context, field graphql.CollectedField, obj *Scene) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Scene_duration, func(ctx context.Context) (any, error) { return obj.Duration, nil }, nil, ec.marshalOInt2ᚖint, true, false, ) } func (ec *executionContext) fieldContext_Scene_duration(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Scene", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _Scene_director(ctx context.Context, field graphql.CollectedField, obj *Scene) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Scene_director, func(ctx context.Context) (any, error) { return obj.Director, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_Scene_director(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Scene", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _Scene_code(ctx context.Context, field graphql.CollectedField, obj *Scene) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Scene_code, func(ctx context.Context) (any, error) { return obj.Code, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_Scene_code(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Scene", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _Scene_deleted(ctx context.Context, field graphql.CollectedField, obj *Scene) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Scene_deleted, func(ctx context.Context) (any, error) { return obj.Deleted, nil }, nil, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_Scene_deleted(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Scene", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } return fc, nil } func (ec *executionContext) _Scene_edits(ctx context.Context, field graphql.CollectedField, obj *Scene) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Scene_edits, func(ctx context.Context) (any, error) { return ec.Resolvers.Scene().Edits(ctx, obj) }, nil, ec.marshalNEdit2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditᚄ, true, true, ) } func (ec *executionContext) fieldContext_Scene_edits(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Scene", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Edit_id(ctx, field) case "user": return ec.fieldContext_Edit_user(ctx, field) case "target": return ec.fieldContext_Edit_target(ctx, field) case "target_type": return ec.fieldContext_Edit_target_type(ctx, field) case "merge_sources": return ec.fieldContext_Edit_merge_sources(ctx, field) case "operation": return ec.fieldContext_Edit_operation(ctx, field) case "bot": return ec.fieldContext_Edit_bot(ctx, field) case "details": return ec.fieldContext_Edit_details(ctx, field) case "old_details": return ec.fieldContext_Edit_old_details(ctx, field) case "options": return ec.fieldContext_Edit_options(ctx, field) case "comments": return ec.fieldContext_Edit_comments(ctx, field) case "votes": return ec.fieldContext_Edit_votes(ctx, field) case "vote_count": return ec.fieldContext_Edit_vote_count(ctx, field) case "destructive": return ec.fieldContext_Edit_destructive(ctx, field) case "status": return ec.fieldContext_Edit_status(ctx, field) case "applied": return ec.fieldContext_Edit_applied(ctx, field) case "update_count": return ec.fieldContext_Edit_update_count(ctx, field) case "updatable": return ec.fieldContext_Edit_updatable(ctx, field) case "created": return ec.fieldContext_Edit_created(ctx, field) case "updated": return ec.fieldContext_Edit_updated(ctx, field) case "closed": return ec.fieldContext_Edit_closed(ctx, field) case "expires": return ec.fieldContext_Edit_expires(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Edit", field.Name) }, } return fc, nil } func (ec *executionContext) _Scene_created(ctx context.Context, field graphql.CollectedField, obj *Scene) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Scene_created, func(ctx context.Context) (any, error) { return ec.Resolvers.Scene().Created(ctx, obj) }, nil, ec.marshalNTime2ᚖtimeᚐTime, true, true, ) } func (ec *executionContext) fieldContext_Scene_created(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Scene", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Time does not have child fields") }, } return fc, nil } func (ec *executionContext) _Scene_updated(ctx context.Context, field graphql.CollectedField, obj *Scene) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Scene_updated, func(ctx context.Context) (any, error) { return ec.Resolvers.Scene().Updated(ctx, obj) }, nil, ec.marshalNTime2ᚖtimeᚐTime, true, true, ) } func (ec *executionContext) fieldContext_Scene_updated(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Scene", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Time does not have child fields") }, } return fc, nil } func (ec *executionContext) _SceneDraft_id(ctx context.Context, field graphql.CollectedField, obj *SceneDraft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneDraft_id, func(ctx context.Context) (any, error) { return obj.ID, nil }, nil, ec.marshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID, true, false, ) } func (ec *executionContext) fieldContext_SceneDraft_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneDraft", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type ID does not have child fields") }, } return fc, nil } func (ec *executionContext) _SceneDraft_title(ctx context.Context, field graphql.CollectedField, obj *SceneDraft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneDraft_title, func(ctx context.Context) (any, error) { return obj.Title, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_SceneDraft_title(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneDraft", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _SceneDraft_code(ctx context.Context, field graphql.CollectedField, obj *SceneDraft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneDraft_code, func(ctx context.Context) (any, error) { return obj.Code, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_SceneDraft_code(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneDraft", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _SceneDraft_details(ctx context.Context, field graphql.CollectedField, obj *SceneDraft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneDraft_details, func(ctx context.Context) (any, error) { return obj.Details, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_SceneDraft_details(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneDraft", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _SceneDraft_director(ctx context.Context, field graphql.CollectedField, obj *SceneDraft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneDraft_director, func(ctx context.Context) (any, error) { return obj.Director, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_SceneDraft_director(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneDraft", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _SceneDraft_urls(ctx context.Context, field graphql.CollectedField, obj *SceneDraft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneDraft_urls, func(ctx context.Context) (any, error) { return obj.URLs, nil }, nil, ec.marshalOString2ᚕstringᚄ, true, false, ) } func (ec *executionContext) fieldContext_SceneDraft_urls(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneDraft", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _SceneDraft_date(ctx context.Context, field graphql.CollectedField, obj *SceneDraft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneDraft_date, func(ctx context.Context) (any, error) { return obj.Date, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_SceneDraft_date(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneDraft", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _SceneDraft_production_date(ctx context.Context, field graphql.CollectedField, obj *SceneDraft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneDraft_production_date, func(ctx context.Context) (any, error) { return obj.ProductionDate, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_SceneDraft_production_date(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneDraft", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _SceneDraft_studio(ctx context.Context, field graphql.CollectedField, obj *SceneDraft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneDraft_studio, func(ctx context.Context) (any, error) { return ec.Resolvers.SceneDraft().Studio(ctx, obj) }, nil, ec.marshalOSceneDraftStudio2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneDraftStudio, true, false, ) } func (ec *executionContext) fieldContext_SceneDraft_studio(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneDraft", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type SceneDraftStudio does not have child fields") }, } return fc, nil } func (ec *executionContext) _SceneDraft_performers(ctx context.Context, field graphql.CollectedField, obj *SceneDraft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneDraft_performers, func(ctx context.Context) (any, error) { return ec.Resolvers.SceneDraft().Performers(ctx, obj) }, nil, ec.marshalNSceneDraftPerformer2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneDraftPerformerᚄ, true, true, ) } func (ec *executionContext) fieldContext_SceneDraft_performers(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneDraft", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type SceneDraftPerformer does not have child fields") }, } return fc, nil } func (ec *executionContext) _SceneDraft_tags(ctx context.Context, field graphql.CollectedField, obj *SceneDraft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneDraft_tags, func(ctx context.Context) (any, error) { return ec.Resolvers.SceneDraft().Tags(ctx, obj) }, nil, ec.marshalOSceneDraftTag2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneDraftTagᚄ, true, false, ) } func (ec *executionContext) fieldContext_SceneDraft_tags(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneDraft", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type SceneDraftTag does not have child fields") }, } return fc, nil } func (ec *executionContext) _SceneDraft_image(ctx context.Context, field graphql.CollectedField, obj *SceneDraft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneDraft_image, func(ctx context.Context) (any, error) { return ec.Resolvers.SceneDraft().Image(ctx, obj) }, nil, ec.marshalOImage2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐImage, true, false, ) } func (ec *executionContext) fieldContext_SceneDraft_image(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneDraft", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Image_id(ctx, field) case "url": return ec.fieldContext_Image_url(ctx, field) case "width": return ec.fieldContext_Image_width(ctx, field) case "height": return ec.fieldContext_Image_height(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Image", field.Name) }, } return fc, nil } func (ec *executionContext) _SceneDraft_fingerprints(ctx context.Context, field graphql.CollectedField, obj *SceneDraft) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneDraft_fingerprints, func(ctx context.Context) (any, error) { return obj.Fingerprints, nil }, nil, ec.marshalNDraftFingerprint2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDraftFingerprintᚄ, true, true, ) } func (ec *executionContext) fieldContext_SceneDraft_fingerprints(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneDraft", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "hash": return ec.fieldContext_DraftFingerprint_hash(ctx, field) case "algorithm": return ec.fieldContext_DraftFingerprint_algorithm(ctx, field) case "duration": return ec.fieldContext_DraftFingerprint_duration(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type DraftFingerprint", field.Name) }, } return fc, nil } func (ec *executionContext) _SceneEdit_title(ctx context.Context, field graphql.CollectedField, obj *SceneEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneEdit_title, func(ctx context.Context) (any, error) { return obj.Title, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_SceneEdit_title(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _SceneEdit_details(ctx context.Context, field graphql.CollectedField, obj *SceneEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneEdit_details, func(ctx context.Context) (any, error) { return obj.Details, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_SceneEdit_details(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _SceneEdit_added_urls(ctx context.Context, field graphql.CollectedField, obj *SceneEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneEdit_added_urls, func(ctx context.Context) (any, error) { return obj.AddedUrls, nil }, nil, ec.marshalOURL2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐURLᚄ, true, false, ) } func (ec *executionContext) fieldContext_SceneEdit_added_urls(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "url": return ec.fieldContext_URL_url(ctx, field) case "type": return ec.fieldContext_URL_type(ctx, field) case "site": return ec.fieldContext_URL_site(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type URL", field.Name) }, } return fc, nil } func (ec *executionContext) _SceneEdit_removed_urls(ctx context.Context, field graphql.CollectedField, obj *SceneEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneEdit_removed_urls, func(ctx context.Context) (any, error) { return obj.RemovedUrls, nil }, nil, ec.marshalOURL2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐURLᚄ, true, false, ) } func (ec *executionContext) fieldContext_SceneEdit_removed_urls(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "url": return ec.fieldContext_URL_url(ctx, field) case "type": return ec.fieldContext_URL_type(ctx, field) case "site": return ec.fieldContext_URL_site(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type URL", field.Name) }, } return fc, nil } func (ec *executionContext) _SceneEdit_date(ctx context.Context, field graphql.CollectedField, obj *SceneEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneEdit_date, func(ctx context.Context) (any, error) { return obj.Date, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_SceneEdit_date(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _SceneEdit_production_date(ctx context.Context, field graphql.CollectedField, obj *SceneEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneEdit_production_date, func(ctx context.Context) (any, error) { return obj.ProductionDate, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_SceneEdit_production_date(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _SceneEdit_studio(ctx context.Context, field graphql.CollectedField, obj *SceneEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneEdit_studio, func(ctx context.Context) (any, error) { return ec.Resolvers.SceneEdit().Studio(ctx, obj) }, nil, ec.marshalOStudio2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStudio, true, false, ) } func (ec *executionContext) fieldContext_SceneEdit_studio(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneEdit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Studio_id(ctx, field) case "name": return ec.fieldContext_Studio_name(ctx, field) case "aliases": return ec.fieldContext_Studio_aliases(ctx, field) case "urls": return ec.fieldContext_Studio_urls(ctx, field) case "parent": return ec.fieldContext_Studio_parent(ctx, field) case "child_studios": return ec.fieldContext_Studio_child_studios(ctx, field) case "sub_studios": return ec.fieldContext_Studio_sub_studios(ctx, field) case "images": return ec.fieldContext_Studio_images(ctx, field) case "deleted": return ec.fieldContext_Studio_deleted(ctx, field) case "is_favorite": return ec.fieldContext_Studio_is_favorite(ctx, field) case "created": return ec.fieldContext_Studio_created(ctx, field) case "updated": return ec.fieldContext_Studio_updated(ctx, field) case "performers": return ec.fieldContext_Studio_performers(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Studio", field.Name) }, } return fc, nil } func (ec *executionContext) _SceneEdit_added_performers(ctx context.Context, field graphql.CollectedField, obj *SceneEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneEdit_added_performers, func(ctx context.Context) (any, error) { return ec.Resolvers.SceneEdit().AddedPerformers(ctx, obj) }, nil, ec.marshalOPerformerAppearance2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerAppearanceᚄ, true, false, ) } func (ec *executionContext) fieldContext_SceneEdit_added_performers(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneEdit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "performer": return ec.fieldContext_PerformerAppearance_performer(ctx, field) case "as": return ec.fieldContext_PerformerAppearance_as(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type PerformerAppearance", field.Name) }, } return fc, nil } func (ec *executionContext) _SceneEdit_removed_performers(ctx context.Context, field graphql.CollectedField, obj *SceneEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneEdit_removed_performers, func(ctx context.Context) (any, error) { return ec.Resolvers.SceneEdit().RemovedPerformers(ctx, obj) }, nil, ec.marshalOPerformerAppearance2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerAppearanceᚄ, true, false, ) } func (ec *executionContext) fieldContext_SceneEdit_removed_performers(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneEdit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "performer": return ec.fieldContext_PerformerAppearance_performer(ctx, field) case "as": return ec.fieldContext_PerformerAppearance_as(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type PerformerAppearance", field.Name) }, } return fc, nil } func (ec *executionContext) _SceneEdit_added_tags(ctx context.Context, field graphql.CollectedField, obj *SceneEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneEdit_added_tags, func(ctx context.Context) (any, error) { return ec.Resolvers.SceneEdit().AddedTags(ctx, obj) }, nil, ec.marshalOTag2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagᚄ, true, false, ) } func (ec *executionContext) fieldContext_SceneEdit_added_tags(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneEdit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Tag_id(ctx, field) case "name": return ec.fieldContext_Tag_name(ctx, field) case "description": return ec.fieldContext_Tag_description(ctx, field) case "aliases": return ec.fieldContext_Tag_aliases(ctx, field) case "deleted": return ec.fieldContext_Tag_deleted(ctx, field) case "edits": return ec.fieldContext_Tag_edits(ctx, field) case "category": return ec.fieldContext_Tag_category(ctx, field) case "created": return ec.fieldContext_Tag_created(ctx, field) case "updated": return ec.fieldContext_Tag_updated(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Tag", field.Name) }, } return fc, nil } func (ec *executionContext) _SceneEdit_removed_tags(ctx context.Context, field graphql.CollectedField, obj *SceneEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneEdit_removed_tags, func(ctx context.Context) (any, error) { return ec.Resolvers.SceneEdit().RemovedTags(ctx, obj) }, nil, ec.marshalOTag2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagᚄ, true, false, ) } func (ec *executionContext) fieldContext_SceneEdit_removed_tags(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneEdit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Tag_id(ctx, field) case "name": return ec.fieldContext_Tag_name(ctx, field) case "description": return ec.fieldContext_Tag_description(ctx, field) case "aliases": return ec.fieldContext_Tag_aliases(ctx, field) case "deleted": return ec.fieldContext_Tag_deleted(ctx, field) case "edits": return ec.fieldContext_Tag_edits(ctx, field) case "category": return ec.fieldContext_Tag_category(ctx, field) case "created": return ec.fieldContext_Tag_created(ctx, field) case "updated": return ec.fieldContext_Tag_updated(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Tag", field.Name) }, } return fc, nil } func (ec *executionContext) _SceneEdit_added_images(ctx context.Context, field graphql.CollectedField, obj *SceneEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneEdit_added_images, func(ctx context.Context) (any, error) { return ec.Resolvers.SceneEdit().AddedImages(ctx, obj) }, nil, ec.marshalOImage2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐImageᚄ, true, false, ) } func (ec *executionContext) fieldContext_SceneEdit_added_images(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneEdit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Image_id(ctx, field) case "url": return ec.fieldContext_Image_url(ctx, field) case "width": return ec.fieldContext_Image_width(ctx, field) case "height": return ec.fieldContext_Image_height(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Image", field.Name) }, } return fc, nil } func (ec *executionContext) _SceneEdit_removed_images(ctx context.Context, field graphql.CollectedField, obj *SceneEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneEdit_removed_images, func(ctx context.Context) (any, error) { return ec.Resolvers.SceneEdit().RemovedImages(ctx, obj) }, nil, ec.marshalOImage2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐImageᚄ, true, false, ) } func (ec *executionContext) fieldContext_SceneEdit_removed_images(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneEdit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Image_id(ctx, field) case "url": return ec.fieldContext_Image_url(ctx, field) case "width": return ec.fieldContext_Image_width(ctx, field) case "height": return ec.fieldContext_Image_height(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Image", field.Name) }, } return fc, nil } func (ec *executionContext) _SceneEdit_added_fingerprints(ctx context.Context, field graphql.CollectedField, obj *SceneEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneEdit_added_fingerprints, func(ctx context.Context) (any, error) { return ec.Resolvers.SceneEdit().AddedFingerprints(ctx, obj) }, nil, ec.marshalOFingerprint2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintᚄ, true, false, ) } func (ec *executionContext) fieldContext_SceneEdit_added_fingerprints(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneEdit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "hash": return ec.fieldContext_Fingerprint_hash(ctx, field) case "algorithm": return ec.fieldContext_Fingerprint_algorithm(ctx, field) case "duration": return ec.fieldContext_Fingerprint_duration(ctx, field) case "submissions": return ec.fieldContext_Fingerprint_submissions(ctx, field) case "reports": return ec.fieldContext_Fingerprint_reports(ctx, field) case "created": return ec.fieldContext_Fingerprint_created(ctx, field) case "updated": return ec.fieldContext_Fingerprint_updated(ctx, field) case "user_submitted": return ec.fieldContext_Fingerprint_user_submitted(ctx, field) case "user_reported": return ec.fieldContext_Fingerprint_user_reported(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Fingerprint", field.Name) }, } return fc, nil } func (ec *executionContext) _SceneEdit_removed_fingerprints(ctx context.Context, field graphql.CollectedField, obj *SceneEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneEdit_removed_fingerprints, func(ctx context.Context) (any, error) { return ec.Resolvers.SceneEdit().RemovedFingerprints(ctx, obj) }, nil, ec.marshalOFingerprint2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintᚄ, true, false, ) } func (ec *executionContext) fieldContext_SceneEdit_removed_fingerprints(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneEdit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "hash": return ec.fieldContext_Fingerprint_hash(ctx, field) case "algorithm": return ec.fieldContext_Fingerprint_algorithm(ctx, field) case "duration": return ec.fieldContext_Fingerprint_duration(ctx, field) case "submissions": return ec.fieldContext_Fingerprint_submissions(ctx, field) case "reports": return ec.fieldContext_Fingerprint_reports(ctx, field) case "created": return ec.fieldContext_Fingerprint_created(ctx, field) case "updated": return ec.fieldContext_Fingerprint_updated(ctx, field) case "user_submitted": return ec.fieldContext_Fingerprint_user_submitted(ctx, field) case "user_reported": return ec.fieldContext_Fingerprint_user_reported(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Fingerprint", field.Name) }, } return fc, nil } func (ec *executionContext) _SceneEdit_duration(ctx context.Context, field graphql.CollectedField, obj *SceneEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneEdit_duration, func(ctx context.Context) (any, error) { return obj.Duration, nil }, nil, ec.marshalOInt2ᚖint, true, false, ) } func (ec *executionContext) fieldContext_SceneEdit_duration(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _SceneEdit_director(ctx context.Context, field graphql.CollectedField, obj *SceneEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneEdit_director, func(ctx context.Context) (any, error) { return obj.Director, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_SceneEdit_director(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _SceneEdit_code(ctx context.Context, field graphql.CollectedField, obj *SceneEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneEdit_code, func(ctx context.Context) (any, error) { return obj.Code, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_SceneEdit_code(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _SceneEdit_draft_id(ctx context.Context, field graphql.CollectedField, obj *SceneEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneEdit_draft_id, func(ctx context.Context) (any, error) { return obj.DraftID, nil }, nil, ec.marshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID, true, false, ) } func (ec *executionContext) fieldContext_SceneEdit_draft_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type ID does not have child fields") }, } return fc, nil } func (ec *executionContext) _SceneEdit_urls(ctx context.Context, field graphql.CollectedField, obj *SceneEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneEdit_urls, func(ctx context.Context) (any, error) { return ec.Resolvers.SceneEdit().Urls(ctx, obj) }, nil, ec.marshalNURL2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐURLᚄ, true, true, ) } func (ec *executionContext) fieldContext_SceneEdit_urls(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneEdit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "url": return ec.fieldContext_URL_url(ctx, field) case "type": return ec.fieldContext_URL_type(ctx, field) case "site": return ec.fieldContext_URL_site(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type URL", field.Name) }, } return fc, nil } func (ec *executionContext) _SceneEdit_performers(ctx context.Context, field graphql.CollectedField, obj *SceneEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneEdit_performers, func(ctx context.Context) (any, error) { return ec.Resolvers.SceneEdit().Performers(ctx, obj) }, nil, ec.marshalNPerformerAppearance2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerAppearanceᚄ, true, true, ) } func (ec *executionContext) fieldContext_SceneEdit_performers(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneEdit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "performer": return ec.fieldContext_PerformerAppearance_performer(ctx, field) case "as": return ec.fieldContext_PerformerAppearance_as(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type PerformerAppearance", field.Name) }, } return fc, nil } func (ec *executionContext) _SceneEdit_tags(ctx context.Context, field graphql.CollectedField, obj *SceneEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneEdit_tags, func(ctx context.Context) (any, error) { return ec.Resolvers.SceneEdit().Tags(ctx, obj) }, nil, ec.marshalNTag2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagᚄ, true, true, ) } func (ec *executionContext) fieldContext_SceneEdit_tags(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneEdit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Tag_id(ctx, field) case "name": return ec.fieldContext_Tag_name(ctx, field) case "description": return ec.fieldContext_Tag_description(ctx, field) case "aliases": return ec.fieldContext_Tag_aliases(ctx, field) case "deleted": return ec.fieldContext_Tag_deleted(ctx, field) case "edits": return ec.fieldContext_Tag_edits(ctx, field) case "category": return ec.fieldContext_Tag_category(ctx, field) case "created": return ec.fieldContext_Tag_created(ctx, field) case "updated": return ec.fieldContext_Tag_updated(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Tag", field.Name) }, } return fc, nil } func (ec *executionContext) _SceneEdit_images(ctx context.Context, field graphql.CollectedField, obj *SceneEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneEdit_images, func(ctx context.Context) (any, error) { return ec.Resolvers.SceneEdit().Images(ctx, obj) }, nil, ec.marshalNImage2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐImageᚄ, true, true, ) } func (ec *executionContext) fieldContext_SceneEdit_images(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneEdit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Image_id(ctx, field) case "url": return ec.fieldContext_Image_url(ctx, field) case "width": return ec.fieldContext_Image_width(ctx, field) case "height": return ec.fieldContext_Image_height(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Image", field.Name) }, } return fc, nil } func (ec *executionContext) _SceneEdit_fingerprints(ctx context.Context, field graphql.CollectedField, obj *SceneEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_SceneEdit_fingerprints, func(ctx context.Context) (any, error) { return ec.Resolvers.SceneEdit().Fingerprints(ctx, obj) }, nil, ec.marshalNFingerprint2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintᚄ, true, true, ) } func (ec *executionContext) fieldContext_SceneEdit_fingerprints(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "SceneEdit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "hash": return ec.fieldContext_Fingerprint_hash(ctx, field) case "algorithm": return ec.fieldContext_Fingerprint_algorithm(ctx, field) case "duration": return ec.fieldContext_Fingerprint_duration(ctx, field) case "submissions": return ec.fieldContext_Fingerprint_submissions(ctx, field) case "reports": return ec.fieldContext_Fingerprint_reports(ctx, field) case "created": return ec.fieldContext_Fingerprint_created(ctx, field) case "updated": return ec.fieldContext_Fingerprint_updated(ctx, field) case "user_submitted": return ec.fieldContext_Fingerprint_user_submitted(ctx, field) case "user_reported": return ec.fieldContext_Fingerprint_user_reported(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Fingerprint", field.Name) }, } return fc, nil } func (ec *executionContext) _Site_id(ctx context.Context, field graphql.CollectedField, obj *Site) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Site_id, func(ctx context.Context) (any, error) { return obj.ID, nil }, nil, ec.marshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID, true, true, ) } func (ec *executionContext) fieldContext_Site_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Site", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type ID does not have child fields") }, } return fc, nil } func (ec *executionContext) _Site_name(ctx context.Context, field graphql.CollectedField, obj *Site) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Site_name, func(ctx context.Context) (any, error) { return obj.Name, nil }, nil, ec.marshalNString2string, true, true, ) } func (ec *executionContext) fieldContext_Site_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Site", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _Site_description(ctx context.Context, field graphql.CollectedField, obj *Site) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Site_description, func(ctx context.Context) (any, error) { return obj.Description, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_Site_description(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Site", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _Site_url(ctx context.Context, field graphql.CollectedField, obj *Site) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Site_url, func(ctx context.Context) (any, error) { return obj.URL, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_Site_url(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Site", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _Site_regex(ctx context.Context, field graphql.CollectedField, obj *Site) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Site_regex, func(ctx context.Context) (any, error) { return obj.Regex, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_Site_regex(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Site", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _Site_valid_types(ctx context.Context, field graphql.CollectedField, obj *Site) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Site_valid_types, func(ctx context.Context) (any, error) { return ec.Resolvers.Site().ValidTypes(ctx, obj) }, nil, ec.marshalNValidSiteTypeEnum2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐValidSiteTypeEnumᚄ, true, true, ) } func (ec *executionContext) fieldContext_Site_valid_types(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Site", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type ValidSiteTypeEnum does not have child fields") }, } return fc, nil } func (ec *executionContext) _Site_icon(ctx context.Context, field graphql.CollectedField, obj *Site) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Site_icon, func(ctx context.Context) (any, error) { return ec.Resolvers.Site().Icon(ctx, obj) }, nil, ec.marshalNString2string, true, true, ) } func (ec *executionContext) fieldContext_Site_icon(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Site", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _Site_created(ctx context.Context, field graphql.CollectedField, obj *Site) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Site_created, func(ctx context.Context) (any, error) { return ec.Resolvers.Site().Created(ctx, obj) }, nil, ec.marshalNTime2ᚖtimeᚐTime, true, true, ) } func (ec *executionContext) fieldContext_Site_created(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Site", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Time does not have child fields") }, } return fc, nil } func (ec *executionContext) _Site_updated(ctx context.Context, field graphql.CollectedField, obj *Site) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Site_updated, func(ctx context.Context) (any, error) { return ec.Resolvers.Site().Updated(ctx, obj) }, nil, ec.marshalNTime2ᚖtimeᚐTime, true, true, ) } func (ec *executionContext) fieldContext_Site_updated(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Site", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Time does not have child fields") }, } return fc, nil } func (ec *executionContext) _StashBoxConfig_host_url(ctx context.Context, field graphql.CollectedField, obj *StashBoxConfig) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_StashBoxConfig_host_url, func(ctx context.Context) (any, error) { return obj.HostURL, nil }, nil, ec.marshalNString2string, true, true, ) } func (ec *executionContext) fieldContext_StashBoxConfig_host_url(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "StashBoxConfig", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _StashBoxConfig_require_invite(ctx context.Context, field graphql.CollectedField, obj *StashBoxConfig) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_StashBoxConfig_require_invite, func(ctx context.Context) (any, error) { return obj.RequireInvite, nil }, nil, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_StashBoxConfig_require_invite(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "StashBoxConfig", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } return fc, nil } func (ec *executionContext) _StashBoxConfig_require_activation(ctx context.Context, field graphql.CollectedField, obj *StashBoxConfig) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_StashBoxConfig_require_activation, func(ctx context.Context) (any, error) { return obj.RequireActivation, nil }, nil, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_StashBoxConfig_require_activation(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "StashBoxConfig", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } return fc, nil } func (ec *executionContext) _StashBoxConfig_vote_promotion_threshold(ctx context.Context, field graphql.CollectedField, obj *StashBoxConfig) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_StashBoxConfig_vote_promotion_threshold, func(ctx context.Context) (any, error) { return obj.VotePromotionThreshold, nil }, nil, ec.marshalOInt2ᚖint, true, false, ) } func (ec *executionContext) fieldContext_StashBoxConfig_vote_promotion_threshold(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "StashBoxConfig", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _StashBoxConfig_vote_application_threshold(ctx context.Context, field graphql.CollectedField, obj *StashBoxConfig) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_StashBoxConfig_vote_application_threshold, func(ctx context.Context) (any, error) { return obj.VoteApplicationThreshold, nil }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_StashBoxConfig_vote_application_threshold(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "StashBoxConfig", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _StashBoxConfig_voting_period(ctx context.Context, field graphql.CollectedField, obj *StashBoxConfig) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_StashBoxConfig_voting_period, func(ctx context.Context) (any, error) { return obj.VotingPeriod, nil }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_StashBoxConfig_voting_period(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "StashBoxConfig", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _StashBoxConfig_min_destructive_voting_period(ctx context.Context, field graphql.CollectedField, obj *StashBoxConfig) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_StashBoxConfig_min_destructive_voting_period, func(ctx context.Context) (any, error) { return obj.MinDestructiveVotingPeriod, nil }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_StashBoxConfig_min_destructive_voting_period(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "StashBoxConfig", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _StashBoxConfig_vote_cron_interval(ctx context.Context, field graphql.CollectedField, obj *StashBoxConfig) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_StashBoxConfig_vote_cron_interval, func(ctx context.Context) (any, error) { return obj.VoteCronInterval, nil }, nil, ec.marshalNString2string, true, true, ) } func (ec *executionContext) fieldContext_StashBoxConfig_vote_cron_interval(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "StashBoxConfig", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _StashBoxConfig_guidelines_url(ctx context.Context, field graphql.CollectedField, obj *StashBoxConfig) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_StashBoxConfig_guidelines_url, func(ctx context.Context) (any, error) { return obj.GuidelinesURL, nil }, nil, ec.marshalNString2string, true, true, ) } func (ec *executionContext) fieldContext_StashBoxConfig_guidelines_url(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "StashBoxConfig", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _StashBoxConfig_require_scene_draft(ctx context.Context, field graphql.CollectedField, obj *StashBoxConfig) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_StashBoxConfig_require_scene_draft, func(ctx context.Context) (any, error) { return obj.RequireSceneDraft, nil }, nil, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_StashBoxConfig_require_scene_draft(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "StashBoxConfig", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } return fc, nil } func (ec *executionContext) _StashBoxConfig_edit_update_limit(ctx context.Context, field graphql.CollectedField, obj *StashBoxConfig) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_StashBoxConfig_edit_update_limit, func(ctx context.Context) (any, error) { return obj.EditUpdateLimit, nil }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_StashBoxConfig_edit_update_limit(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "StashBoxConfig", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _StashBoxConfig_require_tag_role(ctx context.Context, field graphql.CollectedField, obj *StashBoxConfig) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_StashBoxConfig_require_tag_role, func(ctx context.Context) (any, error) { return obj.RequireTagRole, nil }, nil, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_StashBoxConfig_require_tag_role(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "StashBoxConfig", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } return fc, nil } func (ec *executionContext) _Studio_id(ctx context.Context, field graphql.CollectedField, obj *Studio) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Studio_id, func(ctx context.Context) (any, error) { return obj.ID, nil }, nil, ec.marshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID, true, true, ) } func (ec *executionContext) fieldContext_Studio_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Studio", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type ID does not have child fields") }, } return fc, nil } func (ec *executionContext) _Studio_name(ctx context.Context, field graphql.CollectedField, obj *Studio) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Studio_name, func(ctx context.Context) (any, error) { return obj.Name, nil }, nil, ec.marshalNString2string, true, true, ) } func (ec *executionContext) fieldContext_Studio_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Studio", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _Studio_aliases(ctx context.Context, field graphql.CollectedField, obj *Studio) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Studio_aliases, func(ctx context.Context) (any, error) { return ec.Resolvers.Studio().Aliases(ctx, obj) }, nil, ec.marshalNString2ᚕstringᚄ, true, true, ) } func (ec *executionContext) fieldContext_Studio_aliases(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Studio", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _Studio_urls(ctx context.Context, field graphql.CollectedField, obj *Studio) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Studio_urls, func(ctx context.Context) (any, error) { return ec.Resolvers.Studio().Urls(ctx, obj) }, nil, ec.marshalNURL2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐURLᚄ, true, true, ) } func (ec *executionContext) fieldContext_Studio_urls(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Studio", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "url": return ec.fieldContext_URL_url(ctx, field) case "type": return ec.fieldContext_URL_type(ctx, field) case "site": return ec.fieldContext_URL_site(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type URL", field.Name) }, } return fc, nil } func (ec *executionContext) _Studio_parent(ctx context.Context, field graphql.CollectedField, obj *Studio) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Studio_parent, func(ctx context.Context) (any, error) { return ec.Resolvers.Studio().Parent(ctx, obj) }, nil, ec.marshalOStudio2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStudio, true, false, ) } func (ec *executionContext) fieldContext_Studio_parent(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Studio", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Studio_id(ctx, field) case "name": return ec.fieldContext_Studio_name(ctx, field) case "aliases": return ec.fieldContext_Studio_aliases(ctx, field) case "urls": return ec.fieldContext_Studio_urls(ctx, field) case "parent": return ec.fieldContext_Studio_parent(ctx, field) case "child_studios": return ec.fieldContext_Studio_child_studios(ctx, field) case "sub_studios": return ec.fieldContext_Studio_sub_studios(ctx, field) case "images": return ec.fieldContext_Studio_images(ctx, field) case "deleted": return ec.fieldContext_Studio_deleted(ctx, field) case "is_favorite": return ec.fieldContext_Studio_is_favorite(ctx, field) case "created": return ec.fieldContext_Studio_created(ctx, field) case "updated": return ec.fieldContext_Studio_updated(ctx, field) case "performers": return ec.fieldContext_Studio_performers(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Studio", field.Name) }, } return fc, nil } func (ec *executionContext) _Studio_child_studios(ctx context.Context, field graphql.CollectedField, obj *Studio) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Studio_child_studios, func(ctx context.Context) (any, error) { return ec.Resolvers.Studio().ChildStudios(ctx, obj) }, nil, ec.marshalNStudio2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStudioᚄ, true, true, ) } func (ec *executionContext) fieldContext_Studio_child_studios(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Studio", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Studio_id(ctx, field) case "name": return ec.fieldContext_Studio_name(ctx, field) case "aliases": return ec.fieldContext_Studio_aliases(ctx, field) case "urls": return ec.fieldContext_Studio_urls(ctx, field) case "parent": return ec.fieldContext_Studio_parent(ctx, field) case "child_studios": return ec.fieldContext_Studio_child_studios(ctx, field) case "sub_studios": return ec.fieldContext_Studio_sub_studios(ctx, field) case "images": return ec.fieldContext_Studio_images(ctx, field) case "deleted": return ec.fieldContext_Studio_deleted(ctx, field) case "is_favorite": return ec.fieldContext_Studio_is_favorite(ctx, field) case "created": return ec.fieldContext_Studio_created(ctx, field) case "updated": return ec.fieldContext_Studio_updated(ctx, field) case "performers": return ec.fieldContext_Studio_performers(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Studio", field.Name) }, } return fc, nil } func (ec *executionContext) _Studio_sub_studios(ctx context.Context, field graphql.CollectedField, obj *Studio) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Studio_sub_studios, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Studio().SubStudios(ctx, obj, fc.Args["input"].(*StudioQueryInput)) }, nil, ec.marshalNQueryStudiosResultType2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐQueryStudiosResultType, true, true, ) } func (ec *executionContext) fieldContext_Studio_sub_studios(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Studio", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "count": return ec.fieldContext_QueryStudiosResultType_count(ctx, field) case "studios": return ec.fieldContext_QueryStudiosResultType_studios(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type QueryStudiosResultType", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Studio_sub_studios_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _Studio_images(ctx context.Context, field graphql.CollectedField, obj *Studio) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Studio_images, func(ctx context.Context) (any, error) { return ec.Resolvers.Studio().Images(ctx, obj) }, nil, ec.marshalNImage2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐImageᚄ, true, true, ) } func (ec *executionContext) fieldContext_Studio_images(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Studio", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Image_id(ctx, field) case "url": return ec.fieldContext_Image_url(ctx, field) case "width": return ec.fieldContext_Image_width(ctx, field) case "height": return ec.fieldContext_Image_height(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Image", field.Name) }, } return fc, nil } func (ec *executionContext) _Studio_deleted(ctx context.Context, field graphql.CollectedField, obj *Studio) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Studio_deleted, func(ctx context.Context) (any, error) { return obj.Deleted, nil }, nil, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_Studio_deleted(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Studio", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } return fc, nil } func (ec *executionContext) _Studio_is_favorite(ctx context.Context, field graphql.CollectedField, obj *Studio) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Studio_is_favorite, func(ctx context.Context) (any, error) { return ec.Resolvers.Studio().IsFavorite(ctx, obj) }, nil, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_Studio_is_favorite(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Studio", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } return fc, nil } func (ec *executionContext) _Studio_created(ctx context.Context, field graphql.CollectedField, obj *Studio) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Studio_created, func(ctx context.Context) (any, error) { return ec.Resolvers.Studio().Created(ctx, obj) }, nil, ec.marshalNTime2ᚖtimeᚐTime, true, true, ) } func (ec *executionContext) fieldContext_Studio_created(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Studio", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Time does not have child fields") }, } return fc, nil } func (ec *executionContext) _Studio_updated(ctx context.Context, field graphql.CollectedField, obj *Studio) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Studio_updated, func(ctx context.Context) (any, error) { return ec.Resolvers.Studio().Updated(ctx, obj) }, nil, ec.marshalNTime2ᚖtimeᚐTime, true, true, ) } func (ec *executionContext) fieldContext_Studio_updated(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Studio", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Time does not have child fields") }, } return fc, nil } func (ec *executionContext) _Studio_performers(ctx context.Context, field graphql.CollectedField, obj *Studio) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Studio_performers, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return ec.Resolvers.Studio().Performers(ctx, obj, fc.Args["input"].(PerformerQueryInput)) }, nil, ec.marshalNQueryPerformersResultType2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerQuery, true, true, ) } func (ec *executionContext) fieldContext_Studio_performers(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Studio", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "count": return ec.fieldContext_QueryPerformersResultType_count(ctx, field) case "performers": return ec.fieldContext_QueryPerformersResultType_performers(ctx, field) case "facets": return ec.fieldContext_QueryPerformersResultType_facets(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type QueryPerformersResultType", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field_Studio_performers_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) _StudioEdit_name(ctx context.Context, field graphql.CollectedField, obj *StudioEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_StudioEdit_name, func(ctx context.Context) (any, error) { return obj.Name, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_StudioEdit_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "StudioEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _StudioEdit_added_urls(ctx context.Context, field graphql.CollectedField, obj *StudioEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_StudioEdit_added_urls, func(ctx context.Context) (any, error) { return obj.AddedUrls, nil }, nil, ec.marshalOURL2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐURLᚄ, true, false, ) } func (ec *executionContext) fieldContext_StudioEdit_added_urls(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "StudioEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "url": return ec.fieldContext_URL_url(ctx, field) case "type": return ec.fieldContext_URL_type(ctx, field) case "site": return ec.fieldContext_URL_site(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type URL", field.Name) }, } return fc, nil } func (ec *executionContext) _StudioEdit_removed_urls(ctx context.Context, field graphql.CollectedField, obj *StudioEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_StudioEdit_removed_urls, func(ctx context.Context) (any, error) { return obj.RemovedUrls, nil }, nil, ec.marshalOURL2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐURLᚄ, true, false, ) } func (ec *executionContext) fieldContext_StudioEdit_removed_urls(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "StudioEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "url": return ec.fieldContext_URL_url(ctx, field) case "type": return ec.fieldContext_URL_type(ctx, field) case "site": return ec.fieldContext_URL_site(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type URL", field.Name) }, } return fc, nil } func (ec *executionContext) _StudioEdit_parent(ctx context.Context, field graphql.CollectedField, obj *StudioEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_StudioEdit_parent, func(ctx context.Context) (any, error) { return ec.Resolvers.StudioEdit().Parent(ctx, obj) }, nil, ec.marshalOStudio2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStudio, true, false, ) } func (ec *executionContext) fieldContext_StudioEdit_parent(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "StudioEdit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Studio_id(ctx, field) case "name": return ec.fieldContext_Studio_name(ctx, field) case "aliases": return ec.fieldContext_Studio_aliases(ctx, field) case "urls": return ec.fieldContext_Studio_urls(ctx, field) case "parent": return ec.fieldContext_Studio_parent(ctx, field) case "child_studios": return ec.fieldContext_Studio_child_studios(ctx, field) case "sub_studios": return ec.fieldContext_Studio_sub_studios(ctx, field) case "images": return ec.fieldContext_Studio_images(ctx, field) case "deleted": return ec.fieldContext_Studio_deleted(ctx, field) case "is_favorite": return ec.fieldContext_Studio_is_favorite(ctx, field) case "created": return ec.fieldContext_Studio_created(ctx, field) case "updated": return ec.fieldContext_Studio_updated(ctx, field) case "performers": return ec.fieldContext_Studio_performers(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Studio", field.Name) }, } return fc, nil } func (ec *executionContext) _StudioEdit_added_images(ctx context.Context, field graphql.CollectedField, obj *StudioEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_StudioEdit_added_images, func(ctx context.Context) (any, error) { return ec.Resolvers.StudioEdit().AddedImages(ctx, obj) }, nil, ec.marshalOImage2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐImageᚄ, true, false, ) } func (ec *executionContext) fieldContext_StudioEdit_added_images(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "StudioEdit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Image_id(ctx, field) case "url": return ec.fieldContext_Image_url(ctx, field) case "width": return ec.fieldContext_Image_width(ctx, field) case "height": return ec.fieldContext_Image_height(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Image", field.Name) }, } return fc, nil } func (ec *executionContext) _StudioEdit_removed_images(ctx context.Context, field graphql.CollectedField, obj *StudioEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_StudioEdit_removed_images, func(ctx context.Context) (any, error) { return ec.Resolvers.StudioEdit().RemovedImages(ctx, obj) }, nil, ec.marshalOImage2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐImageᚄ, true, false, ) } func (ec *executionContext) fieldContext_StudioEdit_removed_images(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "StudioEdit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Image_id(ctx, field) case "url": return ec.fieldContext_Image_url(ctx, field) case "width": return ec.fieldContext_Image_width(ctx, field) case "height": return ec.fieldContext_Image_height(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Image", field.Name) }, } return fc, nil } func (ec *executionContext) _StudioEdit_added_aliases(ctx context.Context, field graphql.CollectedField, obj *StudioEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_StudioEdit_added_aliases, func(ctx context.Context) (any, error) { return obj.AddedAliases, nil }, nil, ec.marshalOString2ᚕstringᚄ, true, false, ) } func (ec *executionContext) fieldContext_StudioEdit_added_aliases(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "StudioEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _StudioEdit_removed_aliases(ctx context.Context, field graphql.CollectedField, obj *StudioEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_StudioEdit_removed_aliases, func(ctx context.Context) (any, error) { return obj.RemovedAliases, nil }, nil, ec.marshalOString2ᚕstringᚄ, true, false, ) } func (ec *executionContext) fieldContext_StudioEdit_removed_aliases(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "StudioEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _StudioEdit_images(ctx context.Context, field graphql.CollectedField, obj *StudioEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_StudioEdit_images, func(ctx context.Context) (any, error) { return ec.Resolvers.StudioEdit().Images(ctx, obj) }, nil, ec.marshalNImage2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐImageᚄ, true, true, ) } func (ec *executionContext) fieldContext_StudioEdit_images(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "StudioEdit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Image_id(ctx, field) case "url": return ec.fieldContext_Image_url(ctx, field) case "width": return ec.fieldContext_Image_width(ctx, field) case "height": return ec.fieldContext_Image_height(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Image", field.Name) }, } return fc, nil } func (ec *executionContext) _StudioEdit_urls(ctx context.Context, field graphql.CollectedField, obj *StudioEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_StudioEdit_urls, func(ctx context.Context) (any, error) { return ec.Resolvers.StudioEdit().Urls(ctx, obj) }, nil, ec.marshalNURL2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐURLᚄ, true, true, ) } func (ec *executionContext) fieldContext_StudioEdit_urls(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "StudioEdit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "url": return ec.fieldContext_URL_url(ctx, field) case "type": return ec.fieldContext_URL_type(ctx, field) case "site": return ec.fieldContext_URL_site(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type URL", field.Name) }, } return fc, nil } func (ec *executionContext) _Tag_id(ctx context.Context, field graphql.CollectedField, obj *Tag) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Tag_id, func(ctx context.Context) (any, error) { return obj.ID, nil }, nil, ec.marshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID, true, true, ) } func (ec *executionContext) fieldContext_Tag_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Tag", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type ID does not have child fields") }, } return fc, nil } func (ec *executionContext) _Tag_name(ctx context.Context, field graphql.CollectedField, obj *Tag) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Tag_name, func(ctx context.Context) (any, error) { return obj.Name, nil }, nil, ec.marshalNString2string, true, true, ) } func (ec *executionContext) fieldContext_Tag_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Tag", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _Tag_description(ctx context.Context, field graphql.CollectedField, obj *Tag) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Tag_description, func(ctx context.Context) (any, error) { return obj.Description, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_Tag_description(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Tag", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _Tag_aliases(ctx context.Context, field graphql.CollectedField, obj *Tag) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Tag_aliases, func(ctx context.Context) (any, error) { return ec.Resolvers.Tag().Aliases(ctx, obj) }, nil, ec.marshalNString2ᚕstringᚄ, true, true, ) } func (ec *executionContext) fieldContext_Tag_aliases(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Tag", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _Tag_deleted(ctx context.Context, field graphql.CollectedField, obj *Tag) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Tag_deleted, func(ctx context.Context) (any, error) { return obj.Deleted, nil }, nil, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext_Tag_deleted(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Tag", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } return fc, nil } func (ec *executionContext) _Tag_edits(ctx context.Context, field graphql.CollectedField, obj *Tag) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Tag_edits, func(ctx context.Context) (any, error) { return ec.Resolvers.Tag().Edits(ctx, obj) }, nil, ec.marshalNEdit2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditᚄ, true, true, ) } func (ec *executionContext) fieldContext_Tag_edits(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Tag", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Edit_id(ctx, field) case "user": return ec.fieldContext_Edit_user(ctx, field) case "target": return ec.fieldContext_Edit_target(ctx, field) case "target_type": return ec.fieldContext_Edit_target_type(ctx, field) case "merge_sources": return ec.fieldContext_Edit_merge_sources(ctx, field) case "operation": return ec.fieldContext_Edit_operation(ctx, field) case "bot": return ec.fieldContext_Edit_bot(ctx, field) case "details": return ec.fieldContext_Edit_details(ctx, field) case "old_details": return ec.fieldContext_Edit_old_details(ctx, field) case "options": return ec.fieldContext_Edit_options(ctx, field) case "comments": return ec.fieldContext_Edit_comments(ctx, field) case "votes": return ec.fieldContext_Edit_votes(ctx, field) case "vote_count": return ec.fieldContext_Edit_vote_count(ctx, field) case "destructive": return ec.fieldContext_Edit_destructive(ctx, field) case "status": return ec.fieldContext_Edit_status(ctx, field) case "applied": return ec.fieldContext_Edit_applied(ctx, field) case "update_count": return ec.fieldContext_Edit_update_count(ctx, field) case "updatable": return ec.fieldContext_Edit_updatable(ctx, field) case "created": return ec.fieldContext_Edit_created(ctx, field) case "updated": return ec.fieldContext_Edit_updated(ctx, field) case "closed": return ec.fieldContext_Edit_closed(ctx, field) case "expires": return ec.fieldContext_Edit_expires(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Edit", field.Name) }, } return fc, nil } func (ec *executionContext) _Tag_category(ctx context.Context, field graphql.CollectedField, obj *Tag) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Tag_category, func(ctx context.Context) (any, error) { return ec.Resolvers.Tag().Category(ctx, obj) }, nil, ec.marshalOTagCategory2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagCategory, true, false, ) } func (ec *executionContext) fieldContext_Tag_category(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Tag", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_TagCategory_id(ctx, field) case "name": return ec.fieldContext_TagCategory_name(ctx, field) case "group": return ec.fieldContext_TagCategory_group(ctx, field) case "description": return ec.fieldContext_TagCategory_description(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type TagCategory", field.Name) }, } return fc, nil } func (ec *executionContext) _Tag_created(ctx context.Context, field graphql.CollectedField, obj *Tag) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Tag_created, func(ctx context.Context) (any, error) { return obj.Created, nil }, nil, ec.marshalNTime2timeᚐTime, true, true, ) } func (ec *executionContext) fieldContext_Tag_created(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Tag", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Time does not have child fields") }, } return fc, nil } func (ec *executionContext) _Tag_updated(ctx context.Context, field graphql.CollectedField, obj *Tag) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Tag_updated, func(ctx context.Context) (any, error) { return obj.Updated, nil }, nil, ec.marshalNTime2timeᚐTime, true, true, ) } func (ec *executionContext) fieldContext_Tag_updated(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Tag", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Time does not have child fields") }, } return fc, nil } func (ec *executionContext) _TagCategory_id(ctx context.Context, field graphql.CollectedField, obj *TagCategory) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_TagCategory_id, func(ctx context.Context) (any, error) { return obj.ID, nil }, nil, ec.marshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID, true, true, ) } func (ec *executionContext) fieldContext_TagCategory_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "TagCategory", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type ID does not have child fields") }, } return fc, nil } func (ec *executionContext) _TagCategory_name(ctx context.Context, field graphql.CollectedField, obj *TagCategory) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_TagCategory_name, func(ctx context.Context) (any, error) { return obj.Name, nil }, nil, ec.marshalNString2string, true, true, ) } func (ec *executionContext) fieldContext_TagCategory_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "TagCategory", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _TagCategory_group(ctx context.Context, field graphql.CollectedField, obj *TagCategory) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_TagCategory_group, func(ctx context.Context) (any, error) { return ec.Resolvers.TagCategory().Group(ctx, obj) }, nil, ec.marshalNTagGroupEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagGroupEnum, true, true, ) } func (ec *executionContext) fieldContext_TagCategory_group(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "TagCategory", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type TagGroupEnum does not have child fields") }, } return fc, nil } func (ec *executionContext) _TagCategory_description(ctx context.Context, field graphql.CollectedField, obj *TagCategory) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_TagCategory_description, func(ctx context.Context) (any, error) { return obj.Description, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_TagCategory_description(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "TagCategory", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _TagEdit_name(ctx context.Context, field graphql.CollectedField, obj *TagEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_TagEdit_name, func(ctx context.Context) (any, error) { return obj.Name, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_TagEdit_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "TagEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _TagEdit_description(ctx context.Context, field graphql.CollectedField, obj *TagEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_TagEdit_description, func(ctx context.Context) (any, error) { return obj.Description, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext_TagEdit_description(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "TagEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _TagEdit_added_aliases(ctx context.Context, field graphql.CollectedField, obj *TagEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_TagEdit_added_aliases, func(ctx context.Context) (any, error) { return obj.AddedAliases, nil }, nil, ec.marshalOString2ᚕstringᚄ, true, false, ) } func (ec *executionContext) fieldContext_TagEdit_added_aliases(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "TagEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _TagEdit_removed_aliases(ctx context.Context, field graphql.CollectedField, obj *TagEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_TagEdit_removed_aliases, func(ctx context.Context) (any, error) { return obj.RemovedAliases, nil }, nil, ec.marshalOString2ᚕstringᚄ, true, false, ) } func (ec *executionContext) fieldContext_TagEdit_removed_aliases(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "TagEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _TagEdit_category(ctx context.Context, field graphql.CollectedField, obj *TagEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_TagEdit_category, func(ctx context.Context) (any, error) { return ec.Resolvers.TagEdit().Category(ctx, obj) }, nil, ec.marshalOTagCategory2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagCategory, true, false, ) } func (ec *executionContext) fieldContext_TagEdit_category(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "TagEdit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_TagCategory_id(ctx, field) case "name": return ec.fieldContext_TagCategory_name(ctx, field) case "group": return ec.fieldContext_TagCategory_group(ctx, field) case "description": return ec.fieldContext_TagCategory_description(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type TagCategory", field.Name) }, } return fc, nil } func (ec *executionContext) _TagEdit_aliases(ctx context.Context, field graphql.CollectedField, obj *TagEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_TagEdit_aliases, func(ctx context.Context) (any, error) { return ec.Resolvers.TagEdit().Aliases(ctx, obj) }, nil, ec.marshalNString2ᚕstringᚄ, true, true, ) } func (ec *executionContext) fieldContext_TagEdit_aliases(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "TagEdit", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _URL_url(ctx context.Context, field graphql.CollectedField, obj *URL) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_URL_url, func(ctx context.Context) (any, error) { return obj.URL, nil }, nil, ec.marshalNString2string, true, true, ) } func (ec *executionContext) fieldContext_URL_url(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "URL", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _URL_type(ctx context.Context, field graphql.CollectedField, obj *URL) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_URL_type, func(ctx context.Context) (any, error) { return ec.Resolvers.URL().Type(ctx, obj) }, nil, ec.marshalNString2string, true, true, ) } func (ec *executionContext) fieldContext_URL_type(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "URL", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _URL_site(ctx context.Context, field graphql.CollectedField, obj *URL) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_URL_site, func(ctx context.Context) (any, error) { return ec.Resolvers.URL().Site(ctx, obj) }, nil, ec.marshalNSite2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSite, true, true, ) } func (ec *executionContext) fieldContext_URL_site(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "URL", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Site_id(ctx, field) case "name": return ec.fieldContext_Site_name(ctx, field) case "description": return ec.fieldContext_Site_description(ctx, field) case "url": return ec.fieldContext_Site_url(ctx, field) case "regex": return ec.fieldContext_Site_regex(ctx, field) case "valid_types": return ec.fieldContext_Site_valid_types(ctx, field) case "icon": return ec.fieldContext_Site_icon(ctx, field) case "created": return ec.fieldContext_Site_created(ctx, field) case "updated": return ec.fieldContext_Site_updated(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Site", field.Name) }, } return fc, nil } func (ec *executionContext) _UpdatedEdit_edit(ctx context.Context, field graphql.CollectedField, obj *UpdatedEdit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_UpdatedEdit_edit, func(ctx context.Context) (any, error) { return obj.Edit, nil }, nil, ec.marshalNEdit2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEdit, true, true, ) } func (ec *executionContext) fieldContext_UpdatedEdit_edit(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "UpdatedEdit", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_Edit_id(ctx, field) case "user": return ec.fieldContext_Edit_user(ctx, field) case "target": return ec.fieldContext_Edit_target(ctx, field) case "target_type": return ec.fieldContext_Edit_target_type(ctx, field) case "merge_sources": return ec.fieldContext_Edit_merge_sources(ctx, field) case "operation": return ec.fieldContext_Edit_operation(ctx, field) case "bot": return ec.fieldContext_Edit_bot(ctx, field) case "details": return ec.fieldContext_Edit_details(ctx, field) case "old_details": return ec.fieldContext_Edit_old_details(ctx, field) case "options": return ec.fieldContext_Edit_options(ctx, field) case "comments": return ec.fieldContext_Edit_comments(ctx, field) case "votes": return ec.fieldContext_Edit_votes(ctx, field) case "vote_count": return ec.fieldContext_Edit_vote_count(ctx, field) case "destructive": return ec.fieldContext_Edit_destructive(ctx, field) case "status": return ec.fieldContext_Edit_status(ctx, field) case "applied": return ec.fieldContext_Edit_applied(ctx, field) case "update_count": return ec.fieldContext_Edit_update_count(ctx, field) case "updatable": return ec.fieldContext_Edit_updatable(ctx, field) case "created": return ec.fieldContext_Edit_created(ctx, field) case "updated": return ec.fieldContext_Edit_updated(ctx, field) case "closed": return ec.fieldContext_Edit_closed(ctx, field) case "expires": return ec.fieldContext_Edit_expires(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type Edit", field.Name) }, } return fc, nil } func (ec *executionContext) _User_id(ctx context.Context, field graphql.CollectedField, obj *User) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_User_id, func(ctx context.Context) (any, error) { return obj.ID, nil }, nil, ec.marshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID, true, true, ) } func (ec *executionContext) fieldContext_User_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "User", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type ID does not have child fields") }, } return fc, nil } func (ec *executionContext) _User_name(ctx context.Context, field graphql.CollectedField, obj *User) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_User_name, func(ctx context.Context) (any, error) { return obj.Name, nil }, nil, ec.marshalNString2string, true, true, ) } func (ec *executionContext) fieldContext_User_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "User", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _User_roles(ctx context.Context, field graphql.CollectedField, obj *User) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_User_roles, func(ctx context.Context) (any, error) { return ec.Resolvers.User().Roles(ctx, obj) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { if ec.Directives.IsUserOwner == nil { var zeroVal []RoleEnum return zeroVal, errors.New("directive isUserOwner is not implemented") } return ec.Directives.IsUserOwner(ctx, obj, directive0) } next = directive1 return next }, ec.marshalORoleEnum2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnumᚄ, true, false, ) } func (ec *executionContext) fieldContext_User_roles(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "User", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type RoleEnum does not have child fields") }, } return fc, nil } func (ec *executionContext) _User_email(ctx context.Context, field graphql.CollectedField, obj *User) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_User_email, func(ctx context.Context) (any, error) { return obj.Email, nil }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { if ec.Directives.IsUserOwner == nil { var zeroVal string return zeroVal, errors.New("directive isUserOwner is not implemented") } return ec.Directives.IsUserOwner(ctx, obj, directive0) } next = directive1 return next }, ec.marshalOString2string, true, false, ) } func (ec *executionContext) fieldContext_User_email(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "User", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _User_api_key(ctx context.Context, field graphql.CollectedField, obj *User) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_User_api_key, func(ctx context.Context) (any, error) { return obj.APIKey, nil }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { if ec.Directives.IsUserOwner == nil { var zeroVal string return zeroVal, errors.New("directive isUserOwner is not implemented") } return ec.Directives.IsUserOwner(ctx, obj, directive0) } next = directive1 return next }, ec.marshalOString2string, true, false, ) } func (ec *executionContext) fieldContext_User_api_key(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "User", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _User_notification_subscriptions(ctx context.Context, field graphql.CollectedField, obj *User) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_User_notification_subscriptions, func(ctx context.Context) (any, error) { return ec.Resolvers.User().NotificationSubscriptions(ctx, obj) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { if ec.Directives.IsUserOwner == nil { var zeroVal []NotificationEnum return zeroVal, errors.New("directive isUserOwner is not implemented") } return ec.Directives.IsUserOwner(ctx, obj, directive0) } next = directive1 return next }, ec.marshalNNotificationEnum2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐNotificationEnumᚄ, true, true, ) } func (ec *executionContext) fieldContext_User_notification_subscriptions(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "User", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type NotificationEnum does not have child fields") }, } return fc, nil } func (ec *executionContext) _User_vote_count(ctx context.Context, field graphql.CollectedField, obj *User) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_User_vote_count, func(ctx context.Context) (any, error) { return ec.Resolvers.User().VoteCount(ctx, obj) }, nil, ec.marshalNUserVoteCount2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUserVoteCount, true, true, ) } func (ec *executionContext) fieldContext_User_vote_count(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "User", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "abstain": return ec.fieldContext_UserVoteCount_abstain(ctx, field) case "accept": return ec.fieldContext_UserVoteCount_accept(ctx, field) case "reject": return ec.fieldContext_UserVoteCount_reject(ctx, field) case "immediate_accept": return ec.fieldContext_UserVoteCount_immediate_accept(ctx, field) case "immediate_reject": return ec.fieldContext_UserVoteCount_immediate_reject(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type UserVoteCount", field.Name) }, } return fc, nil } func (ec *executionContext) _User_edit_count(ctx context.Context, field graphql.CollectedField, obj *User) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_User_edit_count, func(ctx context.Context) (any, error) { return ec.Resolvers.User().EditCount(ctx, obj) }, nil, ec.marshalNUserEditCount2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUserEditCount, true, true, ) } func (ec *executionContext) fieldContext_User_edit_count(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "User", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "accepted": return ec.fieldContext_UserEditCount_accepted(ctx, field) case "rejected": return ec.fieldContext_UserEditCount_rejected(ctx, field) case "pending": return ec.fieldContext_UserEditCount_pending(ctx, field) case "immediate_accepted": return ec.fieldContext_UserEditCount_immediate_accepted(ctx, field) case "immediate_rejected": return ec.fieldContext_UserEditCount_immediate_rejected(ctx, field) case "failed": return ec.fieldContext_UserEditCount_failed(ctx, field) case "canceled": return ec.fieldContext_UserEditCount_canceled(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type UserEditCount", field.Name) }, } return fc, nil } func (ec *executionContext) _User_api_calls(ctx context.Context, field graphql.CollectedField, obj *User) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_User_api_calls, func(ctx context.Context) (any, error) { return obj.APICalls, nil }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { if ec.Directives.IsUserOwner == nil { var zeroVal int return zeroVal, errors.New("directive isUserOwner is not implemented") } return ec.Directives.IsUserOwner(ctx, obj, directive0) } next = directive1 return next }, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_User_api_calls(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "User", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _User_invited_by(ctx context.Context, field graphql.CollectedField, obj *User) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_User_invited_by, func(ctx context.Context) (any, error) { return ec.Resolvers.User().InvitedBy(ctx, obj) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { if ec.Directives.IsUserOwner == nil { var zeroVal *User return zeroVal, errors.New("directive isUserOwner is not implemented") } return ec.Directives.IsUserOwner(ctx, obj, directive0) } next = directive1 return next }, ec.marshalOUser2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUser, true, false, ) } func (ec *executionContext) fieldContext_User_invited_by(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "User", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_User_id(ctx, field) case "name": return ec.fieldContext_User_name(ctx, field) case "roles": return ec.fieldContext_User_roles(ctx, field) case "email": return ec.fieldContext_User_email(ctx, field) case "api_key": return ec.fieldContext_User_api_key(ctx, field) case "notification_subscriptions": return ec.fieldContext_User_notification_subscriptions(ctx, field) case "vote_count": return ec.fieldContext_User_vote_count(ctx, field) case "edit_count": return ec.fieldContext_User_edit_count(ctx, field) case "api_calls": return ec.fieldContext_User_api_calls(ctx, field) case "invited_by": return ec.fieldContext_User_invited_by(ctx, field) case "invite_tokens": return ec.fieldContext_User_invite_tokens(ctx, field) case "active_invite_codes": return ec.fieldContext_User_active_invite_codes(ctx, field) case "invite_codes": return ec.fieldContext_User_invite_codes(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type User", field.Name) }, } return fc, nil } func (ec *executionContext) _User_invite_tokens(ctx context.Context, field graphql.CollectedField, obj *User) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_User_invite_tokens, func(ctx context.Context) (any, error) { return obj.InviteTokens, nil }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { if ec.Directives.IsUserOwner == nil { var zeroVal int return zeroVal, errors.New("directive isUserOwner is not implemented") } return ec.Directives.IsUserOwner(ctx, obj, directive0) } next = directive1 return next }, ec.marshalOInt2int, true, false, ) } func (ec *executionContext) fieldContext_User_invite_tokens(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "User", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _User_active_invite_codes(ctx context.Context, field graphql.CollectedField, obj *User) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_User_active_invite_codes, func(ctx context.Context) (any, error) { return ec.Resolvers.User().ActiveInviteCodes(ctx, obj) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { if ec.Directives.IsUserOwner == nil { var zeroVal []string return zeroVal, errors.New("directive isUserOwner is not implemented") } return ec.Directives.IsUserOwner(ctx, obj, directive0) } next = directive1 return next }, ec.marshalOString2ᚕstringᚄ, true, false, ) } func (ec *executionContext) fieldContext_User_active_invite_codes(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "User", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _User_invite_codes(ctx context.Context, field graphql.CollectedField, obj *User) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_User_invite_codes, func(ctx context.Context) (any, error) { return ec.Resolvers.User().InviteCodes(ctx, obj) }, func(ctx context.Context, next graphql.Resolver) graphql.Resolver { directive0 := next directive1 := func(ctx context.Context) (any, error) { if ec.Directives.IsUserOwner == nil { var zeroVal []InviteKey return zeroVal, errors.New("directive isUserOwner is not implemented") } return ec.Directives.IsUserOwner(ctx, obj, directive0) } next = directive1 return next }, ec.marshalOInviteKey2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐInviteKeyᚄ, true, false, ) } func (ec *executionContext) fieldContext_User_invite_codes(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "User", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": return ec.fieldContext_InviteKey_id(ctx, field) case "uses": return ec.fieldContext_InviteKey_uses(ctx, field) case "expires": return ec.fieldContext_InviteKey_expires(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type InviteKey", field.Name) }, } return fc, nil } func (ec *executionContext) _UserEditCount_accepted(ctx context.Context, field graphql.CollectedField, obj *UserEditCount) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_UserEditCount_accepted, func(ctx context.Context) (any, error) { return obj.Accepted, nil }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_UserEditCount_accepted(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "UserEditCount", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _UserEditCount_rejected(ctx context.Context, field graphql.CollectedField, obj *UserEditCount) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_UserEditCount_rejected, func(ctx context.Context) (any, error) { return obj.Rejected, nil }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_UserEditCount_rejected(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "UserEditCount", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _UserEditCount_pending(ctx context.Context, field graphql.CollectedField, obj *UserEditCount) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_UserEditCount_pending, func(ctx context.Context) (any, error) { return obj.Pending, nil }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_UserEditCount_pending(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "UserEditCount", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _UserEditCount_immediate_accepted(ctx context.Context, field graphql.CollectedField, obj *UserEditCount) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_UserEditCount_immediate_accepted, func(ctx context.Context) (any, error) { return obj.ImmediateAccepted, nil }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_UserEditCount_immediate_accepted(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "UserEditCount", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _UserEditCount_immediate_rejected(ctx context.Context, field graphql.CollectedField, obj *UserEditCount) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_UserEditCount_immediate_rejected, func(ctx context.Context) (any, error) { return obj.ImmediateRejected, nil }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_UserEditCount_immediate_rejected(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "UserEditCount", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _UserEditCount_failed(ctx context.Context, field graphql.CollectedField, obj *UserEditCount) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_UserEditCount_failed, func(ctx context.Context) (any, error) { return obj.Failed, nil }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_UserEditCount_failed(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "UserEditCount", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _UserEditCount_canceled(ctx context.Context, field graphql.CollectedField, obj *UserEditCount) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_UserEditCount_canceled, func(ctx context.Context) (any, error) { return obj.Canceled, nil }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_UserEditCount_canceled(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "UserEditCount", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _UserVoteCount_abstain(ctx context.Context, field graphql.CollectedField, obj *UserVoteCount) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_UserVoteCount_abstain, func(ctx context.Context) (any, error) { return obj.Abstain, nil }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_UserVoteCount_abstain(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "UserVoteCount", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _UserVoteCount_accept(ctx context.Context, field graphql.CollectedField, obj *UserVoteCount) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_UserVoteCount_accept, func(ctx context.Context) (any, error) { return obj.Accept, nil }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_UserVoteCount_accept(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "UserVoteCount", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _UserVoteCount_reject(ctx context.Context, field graphql.CollectedField, obj *UserVoteCount) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_UserVoteCount_reject, func(ctx context.Context) (any, error) { return obj.Reject, nil }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_UserVoteCount_reject(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "UserVoteCount", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _UserVoteCount_immediate_accept(ctx context.Context, field graphql.CollectedField, obj *UserVoteCount) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_UserVoteCount_immediate_accept, func(ctx context.Context) (any, error) { return obj.ImmediateAccept, nil }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_UserVoteCount_immediate_accept(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "UserVoteCount", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _UserVoteCount_immediate_reject(ctx context.Context, field graphql.CollectedField, obj *UserVoteCount) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_UserVoteCount_immediate_reject, func(ctx context.Context) (any, error) { return obj.ImmediateReject, nil }, nil, ec.marshalNInt2int, true, true, ) } func (ec *executionContext) fieldContext_UserVoteCount_immediate_reject(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "UserVoteCount", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Int does not have child fields") }, } return fc, nil } func (ec *executionContext) _Version_hash(ctx context.Context, field graphql.CollectedField, obj *Version) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Version_hash, func(ctx context.Context) (any, error) { return obj.Hash, nil }, nil, ec.marshalNString2string, true, true, ) } func (ec *executionContext) fieldContext_Version_hash(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Version", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _Version_build_time(ctx context.Context, field graphql.CollectedField, obj *Version) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Version_build_time, func(ctx context.Context) (any, error) { return obj.BuildTime, nil }, nil, ec.marshalNString2string, true, true, ) } func (ec *executionContext) fieldContext_Version_build_time(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Version", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _Version_build_type(ctx context.Context, field graphql.CollectedField, obj *Version) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Version_build_type, func(ctx context.Context) (any, error) { return obj.BuildType, nil }, nil, ec.marshalNString2string, true, true, ) } func (ec *executionContext) fieldContext_Version_build_type(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Version", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) _Version_version(ctx context.Context, field graphql.CollectedField, obj *Version) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext_Version_version, func(ctx context.Context) (any, error) { return obj.Version, nil }, nil, ec.marshalNString2string, true, true, ) } func (ec *executionContext) fieldContext_Version_version(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Version", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) ___Directive_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___Directive_name, func(ctx context.Context) (any, error) { return obj.Name, nil }, nil, ec.marshalNString2string, true, true, ) } func (ec *executionContext) fieldContext___Directive_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Directive", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) ___Directive_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___Directive_description, func(ctx context.Context) (any, error) { return obj.Description(), nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext___Directive_description(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Directive", Field: field, IsMethod: true, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) ___Directive_isRepeatable(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___Directive_isRepeatable, func(ctx context.Context) (any, error) { return obj.IsRepeatable, nil }, nil, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext___Directive_isRepeatable(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Directive", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } return fc, nil } func (ec *executionContext) ___Directive_locations(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___Directive_locations, func(ctx context.Context) (any, error) { return obj.Locations, nil }, nil, ec.marshalN__DirectiveLocation2ᚕstringᚄ, true, true, ) } func (ec *executionContext) fieldContext___Directive_locations(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Directive", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type __DirectiveLocation does not have child fields") }, } return fc, nil } func (ec *executionContext) ___Directive_args(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___Directive_args, func(ctx context.Context) (any, error) { return obj.Args, nil }, nil, ec.marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ, true, true, ) } func (ec *executionContext) fieldContext___Directive_args(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Directive", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "name": return ec.fieldContext___InputValue_name(ctx, field) case "description": return ec.fieldContext___InputValue_description(ctx, field) case "type": return ec.fieldContext___InputValue_type(ctx, field) case "defaultValue": return ec.fieldContext___InputValue_defaultValue(ctx, field) case "isDeprecated": return ec.fieldContext___InputValue_isDeprecated(ctx, field) case "deprecationReason": return ec.fieldContext___InputValue_deprecationReason(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type __InputValue", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field___Directive_args_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) ___EnumValue_name(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___EnumValue_name, func(ctx context.Context) (any, error) { return obj.Name, nil }, nil, ec.marshalNString2string, true, true, ) } func (ec *executionContext) fieldContext___EnumValue_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__EnumValue", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) ___EnumValue_description(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___EnumValue_description, func(ctx context.Context) (any, error) { return obj.Description(), nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext___EnumValue_description(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__EnumValue", Field: field, IsMethod: true, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) ___EnumValue_isDeprecated(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___EnumValue_isDeprecated, func(ctx context.Context) (any, error) { return obj.IsDeprecated(), nil }, nil, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext___EnumValue_isDeprecated(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__EnumValue", Field: field, IsMethod: true, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } return fc, nil } func (ec *executionContext) ___EnumValue_deprecationReason(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___EnumValue_deprecationReason, func(ctx context.Context) (any, error) { return obj.DeprecationReason(), nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext___EnumValue_deprecationReason(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__EnumValue", Field: field, IsMethod: true, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) ___Field_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___Field_name, func(ctx context.Context) (any, error) { return obj.Name, nil }, nil, ec.marshalNString2string, true, true, ) } func (ec *executionContext) fieldContext___Field_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Field", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) ___Field_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___Field_description, func(ctx context.Context) (any, error) { return obj.Description(), nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext___Field_description(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Field", Field: field, IsMethod: true, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) ___Field_args(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___Field_args, func(ctx context.Context) (any, error) { return obj.Args, nil }, nil, ec.marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ, true, true, ) } func (ec *executionContext) fieldContext___Field_args(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Field", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "name": return ec.fieldContext___InputValue_name(ctx, field) case "description": return ec.fieldContext___InputValue_description(ctx, field) case "type": return ec.fieldContext___InputValue_type(ctx, field) case "defaultValue": return ec.fieldContext___InputValue_defaultValue(ctx, field) case "isDeprecated": return ec.fieldContext___InputValue_isDeprecated(ctx, field) case "deprecationReason": return ec.fieldContext___InputValue_deprecationReason(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type __InputValue", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field___Field_args_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) ___Field_type(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___Field_type, func(ctx context.Context) (any, error) { return obj.Type, nil }, nil, ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType, true, true, ) } func (ec *executionContext) fieldContext___Field_type(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Field", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "kind": return ec.fieldContext___Type_kind(ctx, field) case "name": return ec.fieldContext___Type_name(ctx, field) case "description": return ec.fieldContext___Type_description(ctx, field) case "specifiedByURL": return ec.fieldContext___Type_specifiedByURL(ctx, field) case "fields": return ec.fieldContext___Type_fields(ctx, field) case "interfaces": return ec.fieldContext___Type_interfaces(ctx, field) case "possibleTypes": return ec.fieldContext___Type_possibleTypes(ctx, field) case "enumValues": return ec.fieldContext___Type_enumValues(ctx, field) case "inputFields": return ec.fieldContext___Type_inputFields(ctx, field) case "ofType": return ec.fieldContext___Type_ofType(ctx, field) case "isOneOf": return ec.fieldContext___Type_isOneOf(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) }, } return fc, nil } func (ec *executionContext) ___Field_isDeprecated(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___Field_isDeprecated, func(ctx context.Context) (any, error) { return obj.IsDeprecated(), nil }, nil, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext___Field_isDeprecated(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Field", Field: field, IsMethod: true, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } return fc, nil } func (ec *executionContext) ___Field_deprecationReason(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___Field_deprecationReason, func(ctx context.Context) (any, error) { return obj.DeprecationReason(), nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext___Field_deprecationReason(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Field", Field: field, IsMethod: true, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) ___InputValue_name(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___InputValue_name, func(ctx context.Context) (any, error) { return obj.Name, nil }, nil, ec.marshalNString2string, true, true, ) } func (ec *executionContext) fieldContext___InputValue_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__InputValue", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) ___InputValue_description(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___InputValue_description, func(ctx context.Context) (any, error) { return obj.Description(), nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext___InputValue_description(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__InputValue", Field: field, IsMethod: true, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) ___InputValue_type(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___InputValue_type, func(ctx context.Context) (any, error) { return obj.Type, nil }, nil, ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType, true, true, ) } func (ec *executionContext) fieldContext___InputValue_type(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__InputValue", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "kind": return ec.fieldContext___Type_kind(ctx, field) case "name": return ec.fieldContext___Type_name(ctx, field) case "description": return ec.fieldContext___Type_description(ctx, field) case "specifiedByURL": return ec.fieldContext___Type_specifiedByURL(ctx, field) case "fields": return ec.fieldContext___Type_fields(ctx, field) case "interfaces": return ec.fieldContext___Type_interfaces(ctx, field) case "possibleTypes": return ec.fieldContext___Type_possibleTypes(ctx, field) case "enumValues": return ec.fieldContext___Type_enumValues(ctx, field) case "inputFields": return ec.fieldContext___Type_inputFields(ctx, field) case "ofType": return ec.fieldContext___Type_ofType(ctx, field) case "isOneOf": return ec.fieldContext___Type_isOneOf(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) }, } return fc, nil } func (ec *executionContext) ___InputValue_defaultValue(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___InputValue_defaultValue, func(ctx context.Context) (any, error) { return obj.DefaultValue, nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext___InputValue_defaultValue(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__InputValue", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) ___InputValue_isDeprecated(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___InputValue_isDeprecated, func(ctx context.Context) (any, error) { return obj.IsDeprecated(), nil }, nil, ec.marshalNBoolean2bool, true, true, ) } func (ec *executionContext) fieldContext___InputValue_isDeprecated(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__InputValue", Field: field, IsMethod: true, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } return fc, nil } func (ec *executionContext) ___InputValue_deprecationReason(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___InputValue_deprecationReason, func(ctx context.Context) (any, error) { return obj.DeprecationReason(), nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext___InputValue_deprecationReason(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__InputValue", Field: field, IsMethod: true, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) ___Schema_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___Schema_description, func(ctx context.Context) (any, error) { return obj.Description(), nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext___Schema_description(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Schema", Field: field, IsMethod: true, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) ___Schema_types(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___Schema_types, func(ctx context.Context) (any, error) { return obj.Types(), nil }, nil, ec.marshalN__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ, true, true, ) } func (ec *executionContext) fieldContext___Schema_types(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Schema", Field: field, IsMethod: true, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "kind": return ec.fieldContext___Type_kind(ctx, field) case "name": return ec.fieldContext___Type_name(ctx, field) case "description": return ec.fieldContext___Type_description(ctx, field) case "specifiedByURL": return ec.fieldContext___Type_specifiedByURL(ctx, field) case "fields": return ec.fieldContext___Type_fields(ctx, field) case "interfaces": return ec.fieldContext___Type_interfaces(ctx, field) case "possibleTypes": return ec.fieldContext___Type_possibleTypes(ctx, field) case "enumValues": return ec.fieldContext___Type_enumValues(ctx, field) case "inputFields": return ec.fieldContext___Type_inputFields(ctx, field) case "ofType": return ec.fieldContext___Type_ofType(ctx, field) case "isOneOf": return ec.fieldContext___Type_isOneOf(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) }, } return fc, nil } func (ec *executionContext) ___Schema_queryType(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___Schema_queryType, func(ctx context.Context) (any, error) { return obj.QueryType(), nil }, nil, ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType, true, true, ) } func (ec *executionContext) fieldContext___Schema_queryType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Schema", Field: field, IsMethod: true, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "kind": return ec.fieldContext___Type_kind(ctx, field) case "name": return ec.fieldContext___Type_name(ctx, field) case "description": return ec.fieldContext___Type_description(ctx, field) case "specifiedByURL": return ec.fieldContext___Type_specifiedByURL(ctx, field) case "fields": return ec.fieldContext___Type_fields(ctx, field) case "interfaces": return ec.fieldContext___Type_interfaces(ctx, field) case "possibleTypes": return ec.fieldContext___Type_possibleTypes(ctx, field) case "enumValues": return ec.fieldContext___Type_enumValues(ctx, field) case "inputFields": return ec.fieldContext___Type_inputFields(ctx, field) case "ofType": return ec.fieldContext___Type_ofType(ctx, field) case "isOneOf": return ec.fieldContext___Type_isOneOf(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) }, } return fc, nil } func (ec *executionContext) ___Schema_mutationType(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___Schema_mutationType, func(ctx context.Context) (any, error) { return obj.MutationType(), nil }, nil, ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType, true, false, ) } func (ec *executionContext) fieldContext___Schema_mutationType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Schema", Field: field, IsMethod: true, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "kind": return ec.fieldContext___Type_kind(ctx, field) case "name": return ec.fieldContext___Type_name(ctx, field) case "description": return ec.fieldContext___Type_description(ctx, field) case "specifiedByURL": return ec.fieldContext___Type_specifiedByURL(ctx, field) case "fields": return ec.fieldContext___Type_fields(ctx, field) case "interfaces": return ec.fieldContext___Type_interfaces(ctx, field) case "possibleTypes": return ec.fieldContext___Type_possibleTypes(ctx, field) case "enumValues": return ec.fieldContext___Type_enumValues(ctx, field) case "inputFields": return ec.fieldContext___Type_inputFields(ctx, field) case "ofType": return ec.fieldContext___Type_ofType(ctx, field) case "isOneOf": return ec.fieldContext___Type_isOneOf(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) }, } return fc, nil } func (ec *executionContext) ___Schema_subscriptionType(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___Schema_subscriptionType, func(ctx context.Context) (any, error) { return obj.SubscriptionType(), nil }, nil, ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType, true, false, ) } func (ec *executionContext) fieldContext___Schema_subscriptionType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Schema", Field: field, IsMethod: true, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "kind": return ec.fieldContext___Type_kind(ctx, field) case "name": return ec.fieldContext___Type_name(ctx, field) case "description": return ec.fieldContext___Type_description(ctx, field) case "specifiedByURL": return ec.fieldContext___Type_specifiedByURL(ctx, field) case "fields": return ec.fieldContext___Type_fields(ctx, field) case "interfaces": return ec.fieldContext___Type_interfaces(ctx, field) case "possibleTypes": return ec.fieldContext___Type_possibleTypes(ctx, field) case "enumValues": return ec.fieldContext___Type_enumValues(ctx, field) case "inputFields": return ec.fieldContext___Type_inputFields(ctx, field) case "ofType": return ec.fieldContext___Type_ofType(ctx, field) case "isOneOf": return ec.fieldContext___Type_isOneOf(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) }, } return fc, nil } func (ec *executionContext) ___Schema_directives(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___Schema_directives, func(ctx context.Context) (any, error) { return obj.Directives(), nil }, nil, ec.marshalN__Directive2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirectiveᚄ, true, true, ) } func (ec *executionContext) fieldContext___Schema_directives(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Schema", Field: field, IsMethod: true, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "name": return ec.fieldContext___Directive_name(ctx, field) case "description": return ec.fieldContext___Directive_description(ctx, field) case "isRepeatable": return ec.fieldContext___Directive_isRepeatable(ctx, field) case "locations": return ec.fieldContext___Directive_locations(ctx, field) case "args": return ec.fieldContext___Directive_args(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type __Directive", field.Name) }, } return fc, nil } func (ec *executionContext) ___Type_kind(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___Type_kind, func(ctx context.Context) (any, error) { return obj.Kind(), nil }, nil, ec.marshalN__TypeKind2string, true, true, ) } func (ec *executionContext) fieldContext___Type_kind(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Type", Field: field, IsMethod: true, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type __TypeKind does not have child fields") }, } return fc, nil } func (ec *executionContext) ___Type_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___Type_name, func(ctx context.Context) (any, error) { return obj.Name(), nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext___Type_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Type", Field: field, IsMethod: true, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) ___Type_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___Type_description, func(ctx context.Context) (any, error) { return obj.Description(), nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext___Type_description(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Type", Field: field, IsMethod: true, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) ___Type_specifiedByURL(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___Type_specifiedByURL, func(ctx context.Context) (any, error) { return obj.SpecifiedByURL(), nil }, nil, ec.marshalOString2ᚖstring, true, false, ) } func (ec *executionContext) fieldContext___Type_specifiedByURL(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Type", Field: field, IsMethod: true, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } func (ec *executionContext) ___Type_fields(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___Type_fields, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return obj.Fields(fc.Args["includeDeprecated"].(bool)), nil }, nil, ec.marshalO__Field2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐFieldᚄ, true, false, ) } func (ec *executionContext) fieldContext___Type_fields(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Type", Field: field, IsMethod: true, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "name": return ec.fieldContext___Field_name(ctx, field) case "description": return ec.fieldContext___Field_description(ctx, field) case "args": return ec.fieldContext___Field_args(ctx, field) case "type": return ec.fieldContext___Field_type(ctx, field) case "isDeprecated": return ec.fieldContext___Field_isDeprecated(ctx, field) case "deprecationReason": return ec.fieldContext___Field_deprecationReason(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type __Field", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field___Type_fields_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) ___Type_interfaces(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___Type_interfaces, func(ctx context.Context) (any, error) { return obj.Interfaces(), nil }, nil, ec.marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ, true, false, ) } func (ec *executionContext) fieldContext___Type_interfaces(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Type", Field: field, IsMethod: true, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "kind": return ec.fieldContext___Type_kind(ctx, field) case "name": return ec.fieldContext___Type_name(ctx, field) case "description": return ec.fieldContext___Type_description(ctx, field) case "specifiedByURL": return ec.fieldContext___Type_specifiedByURL(ctx, field) case "fields": return ec.fieldContext___Type_fields(ctx, field) case "interfaces": return ec.fieldContext___Type_interfaces(ctx, field) case "possibleTypes": return ec.fieldContext___Type_possibleTypes(ctx, field) case "enumValues": return ec.fieldContext___Type_enumValues(ctx, field) case "inputFields": return ec.fieldContext___Type_inputFields(ctx, field) case "ofType": return ec.fieldContext___Type_ofType(ctx, field) case "isOneOf": return ec.fieldContext___Type_isOneOf(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) }, } return fc, nil } func (ec *executionContext) ___Type_possibleTypes(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___Type_possibleTypes, func(ctx context.Context) (any, error) { return obj.PossibleTypes(), nil }, nil, ec.marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ, true, false, ) } func (ec *executionContext) fieldContext___Type_possibleTypes(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Type", Field: field, IsMethod: true, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "kind": return ec.fieldContext___Type_kind(ctx, field) case "name": return ec.fieldContext___Type_name(ctx, field) case "description": return ec.fieldContext___Type_description(ctx, field) case "specifiedByURL": return ec.fieldContext___Type_specifiedByURL(ctx, field) case "fields": return ec.fieldContext___Type_fields(ctx, field) case "interfaces": return ec.fieldContext___Type_interfaces(ctx, field) case "possibleTypes": return ec.fieldContext___Type_possibleTypes(ctx, field) case "enumValues": return ec.fieldContext___Type_enumValues(ctx, field) case "inputFields": return ec.fieldContext___Type_inputFields(ctx, field) case "ofType": return ec.fieldContext___Type_ofType(ctx, field) case "isOneOf": return ec.fieldContext___Type_isOneOf(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) }, } return fc, nil } func (ec *executionContext) ___Type_enumValues(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___Type_enumValues, func(ctx context.Context) (any, error) { fc := graphql.GetFieldContext(ctx) return obj.EnumValues(fc.Args["includeDeprecated"].(bool)), nil }, nil, ec.marshalO__EnumValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValueᚄ, true, false, ) } func (ec *executionContext) fieldContext___Type_enumValues(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Type", Field: field, IsMethod: true, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "name": return ec.fieldContext___EnumValue_name(ctx, field) case "description": return ec.fieldContext___EnumValue_description(ctx, field) case "isDeprecated": return ec.fieldContext___EnumValue_isDeprecated(ctx, field) case "deprecationReason": return ec.fieldContext___EnumValue_deprecationReason(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type __EnumValue", field.Name) }, } defer func() { if r := recover(); r != nil { err = ec.Recover(ctx, r) ec.Error(ctx, err) } }() ctx = graphql.WithFieldContext(ctx, fc) if fc.Args, err = ec.field___Type_enumValues_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } func (ec *executionContext) ___Type_inputFields(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___Type_inputFields, func(ctx context.Context) (any, error) { return obj.InputFields(), nil }, nil, ec.marshalO__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ, true, false, ) } func (ec *executionContext) fieldContext___Type_inputFields(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Type", Field: field, IsMethod: true, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "name": return ec.fieldContext___InputValue_name(ctx, field) case "description": return ec.fieldContext___InputValue_description(ctx, field) case "type": return ec.fieldContext___InputValue_type(ctx, field) case "defaultValue": return ec.fieldContext___InputValue_defaultValue(ctx, field) case "isDeprecated": return ec.fieldContext___InputValue_isDeprecated(ctx, field) case "deprecationReason": return ec.fieldContext___InputValue_deprecationReason(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type __InputValue", field.Name) }, } return fc, nil } func (ec *executionContext) ___Type_ofType(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___Type_ofType, func(ctx context.Context) (any, error) { return obj.OfType(), nil }, nil, ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType, true, false, ) } func (ec *executionContext) fieldContext___Type_ofType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Type", Field: field, IsMethod: true, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "kind": return ec.fieldContext___Type_kind(ctx, field) case "name": return ec.fieldContext___Type_name(ctx, field) case "description": return ec.fieldContext___Type_description(ctx, field) case "specifiedByURL": return ec.fieldContext___Type_specifiedByURL(ctx, field) case "fields": return ec.fieldContext___Type_fields(ctx, field) case "interfaces": return ec.fieldContext___Type_interfaces(ctx, field) case "possibleTypes": return ec.fieldContext___Type_possibleTypes(ctx, field) case "enumValues": return ec.fieldContext___Type_enumValues(ctx, field) case "inputFields": return ec.fieldContext___Type_inputFields(ctx, field) case "ofType": return ec.fieldContext___Type_ofType(ctx, field) case "isOneOf": return ec.fieldContext___Type_isOneOf(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) }, } return fc, nil } func (ec *executionContext) ___Type_isOneOf(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, ec.OperationContext, field, ec.fieldContext___Type_isOneOf, func(ctx context.Context) (any, error) { return obj.IsOneOf(), nil }, nil, ec.marshalOBoolean2bool, true, false, ) } func (ec *executionContext) fieldContext___Type_isOneOf(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Type", Field: field, IsMethod: true, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type Boolean does not have child fields") }, } return fc, nil } // endregion **************************** field.gotpl ***************************** // region **************************** input.gotpl ***************************** func (ec *executionContext) unmarshalInputActivateNewUserInput(ctx context.Context, obj any) (ActivateNewUserInput, error) { var it ActivateNewUserInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"name", "activation_key", "password"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "name": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) data, err := ec.unmarshalNString2string(ctx, v) if err != nil { return it, err } it.Name = data case "activation_key": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("activation_key")) data, err := ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.ActivationKey = data case "password": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("password")) data, err := ec.unmarshalNString2string(ctx, v) if err != nil { return it, err } it.Password = data } } return it, nil } func (ec *executionContext) unmarshalInputAmendEditInput(ctx context.Context, obj any) (AmendEditInput, error) { var it AmendEditInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"id", "reason", "remove_fields", "remove_added_items", "remove_removed_items"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) data, err := ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.ID = data case "reason": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("reason")) data, err := ec.unmarshalNString2string(ctx, v) if err != nil { return it, err } it.Reason = data case "remove_fields": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("remove_fields")) data, err := ec.unmarshalOString2ᚕstringᚄ(ctx, v) if err != nil { return it, err } it.RemoveFields = data case "remove_added_items": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("remove_added_items")) data, err := ec.unmarshalOAmendItemRemoval2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐAmendItemRemovalᚄ(ctx, v) if err != nil { return it, err } it.RemoveAddedItems = data case "remove_removed_items": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("remove_removed_items")) data, err := ec.unmarshalOAmendItemRemoval2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐAmendItemRemovalᚄ(ctx, v) if err != nil { return it, err } it.RemoveRemovedItems = data } } return it, nil } func (ec *executionContext) unmarshalInputAmendItemRemoval(ctx context.Context, obj any) (AmendItemRemoval, error) { var it AmendItemRemoval if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"field", "indices"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "field": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("field")) data, err := ec.unmarshalNString2string(ctx, v) if err != nil { return it, err } it.Field = data case "indices": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("indices")) data, err := ec.unmarshalNInt2ᚕintᚄ(ctx, v) if err != nil { return it, err } it.Indices = data } } return it, nil } func (ec *executionContext) unmarshalInputApplyEditInput(ctx context.Context, obj any) (ApplyEditInput, error) { var it ApplyEditInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"id"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) data, err := ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.ID = data } } return it, nil } func (ec *executionContext) unmarshalInputBodyModificationCriterionInput(ctx context.Context, obj any) (BodyModificationCriterionInput, error) { var it BodyModificationCriterionInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"location", "description", "modifier"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "location": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("location")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Location = data case "description": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("description")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Description = data case "modifier": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("modifier")) data, err := ec.unmarshalNCriterionModifier2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐCriterionModifier(ctx, v) if err != nil { return it, err } it.Modifier = data } } return it, nil } func (ec *executionContext) unmarshalInputBodyModificationInput(ctx context.Context, obj any) (BodyModificationInput, error) { var it BodyModificationInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"location", "description"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "location": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("location")) data, err := ec.unmarshalNString2string(ctx, v) if err != nil { return it, err } it.Location = data case "description": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("description")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Description = data } } return it, nil } func (ec *executionContext) unmarshalInputBreastTypeCriterionInput(ctx context.Context, obj any) (BreastTypeCriterionInput, error) { var it BreastTypeCriterionInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"value", "modifier"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "value": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("value")) data, err := ec.unmarshalOBreastTypeEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐBreastTypeEnum(ctx, v) if err != nil { return it, err } it.Value = data case "modifier": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("modifier")) data, err := ec.unmarshalNCriterionModifier2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐCriterionModifier(ctx, v) if err != nil { return it, err } it.Modifier = data } } return it, nil } func (ec *executionContext) unmarshalInputCancelEditInput(ctx context.Context, obj any) (CancelEditInput, error) { var it CancelEditInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"id"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) data, err := ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.ID = data } } return it, nil } func (ec *executionContext) unmarshalInputDateCriterionInput(ctx context.Context, obj any) (DateCriterionInput, error) { var it DateCriterionInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"value", "modifier"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "value": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("value")) data, err := ec.unmarshalNDate2string(ctx, v) if err != nil { return it, err } it.Value = data case "modifier": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("modifier")) data, err := ec.unmarshalNCriterionModifier2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐCriterionModifier(ctx, v) if err != nil { return it, err } it.Modifier = data } } return it, nil } func (ec *executionContext) unmarshalInputDeleteEditInput(ctx context.Context, obj any) (DeleteEditInput, error) { var it DeleteEditInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"id", "reason"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) data, err := ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.ID = data case "reason": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("reason")) data, err := ec.unmarshalNString2string(ctx, v) if err != nil { return it, err } it.Reason = data } } return it, nil } func (ec *executionContext) unmarshalInputDeleteFingerprintSubmissionsInput(ctx context.Context, obj any) (DeleteFingerprintSubmissionsInput, error) { var it DeleteFingerprintSubmissionsInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"fingerprints", "scene_id"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "fingerprints": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("fingerprints")) data, err := ec.unmarshalNFingerprintQueryInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintQueryInputᚄ(ctx, v) if err != nil { return it, err } it.Fingerprints = data case "scene_id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("scene_id")) data, err := ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.SceneID = data } } return it, nil } func (ec *executionContext) unmarshalInputDraftEntityInput(ctx context.Context, obj any) (DraftEntityInput, error) { var it DraftEntityInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"name", "id"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "name": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) data, err := ec.unmarshalNString2string(ctx, v) if err != nil { return it, err } it.Name = data case "id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) data, err := ec.unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.ID = data } } return it, nil } func (ec *executionContext) unmarshalInputEditCommentInput(ctx context.Context, obj any) (EditCommentInput, error) { var it EditCommentInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"id", "comment"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) data, err := ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.ID = data case "comment": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("comment")) data, err := ec.unmarshalNString2string(ctx, v) if err != nil { return it, err } it.Comment = data } } return it, nil } func (ec *executionContext) unmarshalInputEditInput(ctx context.Context, obj any) (EditInput, error) { var it EditInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"id", "operation", "merge_source_ids", "comment", "bot"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) data, err := ec.unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.ID = data case "operation": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("operation")) data, err := ec.unmarshalNOperationEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐOperationEnum(ctx, v) if err != nil { return it, err } it.Operation = data case "merge_source_ids": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("merge_source_ids")) data, err := ec.unmarshalOID2ᚕgithubᚗcomᚋgofrsᚋuuidᚐUUIDᚄ(ctx, v) if err != nil { return it, err } it.MergeSourceIds = data case "comment": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("comment")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Comment = data case "bot": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("bot")) data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v) if err != nil { return it, err } it.Bot = data } } return it, nil } func (ec *executionContext) unmarshalInputEditQueryInput(ctx context.Context, obj any) (EditQueryInput, error) { var it EditQueryInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } if _, present := asMap["page"]; !present { asMap["page"] = 1 } if _, present := asMap["per_page"]; !present { asMap["per_page"] = 25 } if _, present := asMap["direction"]; !present { asMap["direction"] = "DESC" } if _, present := asMap["sort"]; !present { asMap["sort"] = "CREATED_AT" } fieldsInOrder := [...]string{"user_id", "status", "operation", "vote_count", "applied", "target_type", "target_id", "is_favorite", "voted", "is_bot", "include_user_submitted", "page", "per_page", "direction", "sort"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "user_id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("user_id")) data, err := ec.unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.UserID = data case "status": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("status")) data, err := ec.unmarshalOVoteStatusEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐVoteStatusEnum(ctx, v) if err != nil { return it, err } it.Status = data case "operation": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("operation")) data, err := ec.unmarshalOOperationEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐOperationEnum(ctx, v) if err != nil { return it, err } it.Operation = data case "vote_count": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("vote_count")) data, err := ec.unmarshalOIntCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐIntCriterionInput(ctx, v) if err != nil { return it, err } it.VoteCount = data case "applied": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("applied")) data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v) if err != nil { return it, err } it.Applied = data case "target_type": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("target_type")) data, err := ec.unmarshalOTargetTypeEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTargetTypeEnum(ctx, v) if err != nil { return it, err } it.TargetType = data case "target_id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("target_id")) data, err := ec.unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.TargetID = data case "is_favorite": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("is_favorite")) data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v) if err != nil { return it, err } it.IsFavorite = data case "voted": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("voted")) data, err := ec.unmarshalOUserVotedFilterEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUserVotedFilterEnum(ctx, v) if err != nil { return it, err } it.Voted = data case "is_bot": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("is_bot")) data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v) if err != nil { return it, err } it.IsBot = data case "include_user_submitted": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("include_user_submitted")) data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v) if err != nil { return it, err } it.IncludeUserSubmitted = data case "page": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("page")) data, err := ec.unmarshalNInt2int(ctx, v) if err != nil { return it, err } it.Page = data case "per_page": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("per_page")) data, err := ec.unmarshalNInt2int(ctx, v) if err != nil { return it, err } it.PerPage = data case "direction": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("direction")) data, err := ec.unmarshalNSortDirectionEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSortDirectionEnum(ctx, v) if err != nil { return it, err } it.Direction = data case "sort": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("sort")) data, err := ec.unmarshalNEditSortEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditSortEnum(ctx, v) if err != nil { return it, err } it.Sort = data } } return it, nil } func (ec *executionContext) unmarshalInputEditVoteInput(ctx context.Context, obj any) (EditVoteInput, error) { var it EditVoteInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"id", "vote"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) data, err := ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.ID = data case "vote": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("vote")) data, err := ec.unmarshalNVoteTypeEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐVoteTypeEnum(ctx, v) if err != nil { return it, err } it.Vote = data } } return it, nil } func (ec *executionContext) unmarshalInputEyeColorCriterionInput(ctx context.Context, obj any) (EyeColorCriterionInput, error) { var it EyeColorCriterionInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"value", "modifier"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "value": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("value")) data, err := ec.unmarshalOEyeColorEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEyeColorEnum(ctx, v) if err != nil { return it, err } it.Value = data case "modifier": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("modifier")) data, err := ec.unmarshalNCriterionModifier2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐCriterionModifier(ctx, v) if err != nil { return it, err } it.Modifier = data } } return it, nil } func (ec *executionContext) unmarshalInputFingerprintBatchSubmission(ctx context.Context, obj any) (FingerprintBatchSubmission, error) { var it FingerprintBatchSubmission if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"scene_id", "hash", "algorithm", "duration"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "scene_id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("scene_id")) data, err := ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.SceneID = data case "hash": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("hash")) data, err := ec.unmarshalNFingerprintHash2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintHash(ctx, v) if err != nil { return it, err } it.Hash = data case "algorithm": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("algorithm")) data, err := ec.unmarshalNFingerprintAlgorithm2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintAlgorithm(ctx, v) if err != nil { return it, err } it.Algorithm = data case "duration": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("duration")) data, err := ec.unmarshalNInt2int(ctx, v) if err != nil { return it, err } it.Duration = data } } return it, nil } func (ec *executionContext) unmarshalInputFingerprintEditInput(ctx context.Context, obj any) (FingerprintEditInput, error) { var it FingerprintEditInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"user_ids", "hash", "algorithm", "duration", "created", "submissions", "updated"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "user_ids": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("user_ids")) data, err := ec.unmarshalOID2ᚕgithubᚗcomᚋgofrsᚋuuidᚐUUIDᚄ(ctx, v) if err != nil { return it, err } it.UserIds = data case "hash": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("hash")) data, err := ec.unmarshalNFingerprintHash2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintHash(ctx, v) if err != nil { return it, err } it.Hash = data case "algorithm": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("algorithm")) data, err := ec.unmarshalNFingerprintAlgorithm2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintAlgorithm(ctx, v) if err != nil { return it, err } it.Algorithm = data case "duration": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("duration")) data, err := ec.unmarshalNInt2int(ctx, v) if err != nil { return it, err } it.Duration = data case "created": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("created")) data, err := ec.unmarshalNTime2timeᚐTime(ctx, v) if err != nil { return it, err } it.Created = data case "submissions": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("submissions")) data, err := ec.unmarshalOInt2ᚖint(ctx, v) if err != nil { return it, err } it.Submissions = data case "updated": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("updated")) data, err := ec.unmarshalOTime2ᚖtimeᚐTime(ctx, v) if err != nil { return it, err } it.Updated = data } } return it, nil } func (ec *executionContext) unmarshalInputFingerprintInput(ctx context.Context, obj any) (FingerprintInput, error) { var it FingerprintInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"user_ids", "hash", "algorithm", "duration"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "user_ids": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("user_ids")) data, err := ec.unmarshalOID2ᚕgithubᚗcomᚋgofrsᚋuuidᚐUUIDᚄ(ctx, v) if err != nil { return it, err } it.UserIds = data case "hash": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("hash")) data, err := ec.unmarshalNFingerprintHash2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintHash(ctx, v) if err != nil { return it, err } it.Hash = data case "algorithm": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("algorithm")) data, err := ec.unmarshalNFingerprintAlgorithm2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintAlgorithm(ctx, v) if err != nil { return it, err } it.Algorithm = data case "duration": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("duration")) data, err := ec.unmarshalNInt2int(ctx, v) if err != nil { return it, err } it.Duration = data } } return it, nil } func (ec *executionContext) unmarshalInputFingerprintQueryInput(ctx context.Context, obj any) (FingerprintQueryInput, error) { var it FingerprintQueryInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"hash", "algorithm"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "hash": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("hash")) data, err := ec.unmarshalNFingerprintHash2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintHash(ctx, v) if err != nil { return it, err } it.Hash = data case "algorithm": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("algorithm")) data, err := ec.unmarshalNFingerprintAlgorithm2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintAlgorithm(ctx, v) if err != nil { return it, err } it.Algorithm = data } } return it, nil } func (ec *executionContext) unmarshalInputFingerprintSubmission(ctx context.Context, obj any) (FingerprintSubmission, error) { var it FingerprintSubmission if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } if _, present := asMap["vote"]; !present { asMap["vote"] = "VALID" } fieldsInOrder := [...]string{"scene_id", "fingerprint", "unmatch", "vote"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "scene_id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("scene_id")) data, err := ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.SceneID = data case "fingerprint": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("fingerprint")) data, err := ec.unmarshalNFingerprintInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintInput(ctx, v) if err != nil { return it, err } it.Fingerprint = data case "unmatch": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("unmatch")) data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v) if err != nil { return it, err } it.Unmatch = data case "vote": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("vote")) data, err := ec.unmarshalOFingerprintSubmissionType2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintSubmissionType(ctx, v) if err != nil { return it, err } it.Vote = data } } return it, nil } func (ec *executionContext) unmarshalInputGenerateInviteCodeInput(ctx context.Context, obj any) (GenerateInviteCodeInput, error) { var it GenerateInviteCodeInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"keys", "uses", "ttl"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "keys": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("keys")) data, err := ec.unmarshalOInt2ᚖint(ctx, v) if err != nil { return it, err } it.Keys = data case "uses": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("uses")) data, err := ec.unmarshalOInt2ᚖint(ctx, v) if err != nil { return it, err } it.Uses = data case "ttl": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("ttl")) data, err := ec.unmarshalOInt2ᚖint(ctx, v) if err != nil { return it, err } it.TTL = data } } return it, nil } func (ec *executionContext) unmarshalInputGrantInviteInput(ctx context.Context, obj any) (GrantInviteInput, error) { var it GrantInviteInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"user_id", "amount"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "user_id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("user_id")) data, err := ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.UserID = data case "amount": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("amount")) data, err := ec.unmarshalNInt2int(ctx, v) if err != nil { return it, err } it.Amount = data } } return it, nil } func (ec *executionContext) unmarshalInputHairColorCriterionInput(ctx context.Context, obj any) (HairColorCriterionInput, error) { var it HairColorCriterionInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"value", "modifier"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "value": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("value")) data, err := ec.unmarshalOHairColorEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐHairColorEnum(ctx, v) if err != nil { return it, err } it.Value = data case "modifier": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("modifier")) data, err := ec.unmarshalNCriterionModifier2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐCriterionModifier(ctx, v) if err != nil { return it, err } it.Modifier = data } } return it, nil } func (ec *executionContext) unmarshalInputIDCriterionInput(ctx context.Context, obj any) (IDCriterionInput, error) { var it IDCriterionInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"value", "modifier"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "value": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("value")) data, err := ec.unmarshalNID2ᚕgithubᚗcomᚋgofrsᚋuuidᚐUUIDᚄ(ctx, v) if err != nil { return it, err } it.Value = data case "modifier": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("modifier")) data, err := ec.unmarshalNCriterionModifier2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐCriterionModifier(ctx, v) if err != nil { return it, err } it.Modifier = data } } return it, nil } func (ec *executionContext) unmarshalInputImageCreateInput(ctx context.Context, obj any) (ImageCreateInput, error) { var it ImageCreateInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"url", "file"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "url": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("url")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.URL = data case "file": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("file")) data, err := ec.unmarshalOUpload2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚐUpload(ctx, v) if err != nil { return it, err } it.File = data } } return it, nil } func (ec *executionContext) unmarshalInputImageDestroyInput(ctx context.Context, obj any) (ImageDestroyInput, error) { var it ImageDestroyInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"id"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) data, err := ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.ID = data } } return it, nil } func (ec *executionContext) unmarshalInputImageUpdateInput(ctx context.Context, obj any) (ImageUpdateInput, error) { var it ImageUpdateInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"id", "url"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) data, err := ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.ID = data case "url": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("url")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.URL = data } } return it, nil } func (ec *executionContext) unmarshalInputIntCriterionInput(ctx context.Context, obj any) (IntCriterionInput, error) { var it IntCriterionInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"value", "modifier"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "value": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("value")) data, err := ec.unmarshalNInt2int(ctx, v) if err != nil { return it, err } it.Value = data case "modifier": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("modifier")) data, err := ec.unmarshalNCriterionModifier2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐCriterionModifier(ctx, v) if err != nil { return it, err } it.Modifier = data } } return it, nil } func (ec *executionContext) unmarshalInputMarkNotificationReadInput(ctx context.Context, obj any) (MarkNotificationReadInput, error) { var it MarkNotificationReadInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"type", "id"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "type": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("type")) data, err := ec.unmarshalNNotificationEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐNotificationEnum(ctx, v) if err != nil { return it, err } it.Type = data case "id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) data, err := ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.ID = data } } return it, nil } func (ec *executionContext) unmarshalInputModAuditQueryInput(ctx context.Context, obj any) (ModAuditQueryInput, error) { var it ModAuditQueryInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } if _, present := asMap["page"]; !present { asMap["page"] = 1 } if _, present := asMap["per_page"]; !present { asMap["per_page"] = 25 } fieldsInOrder := [...]string{"page", "per_page", "action", "user_id"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "page": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("page")) data, err := ec.unmarshalNInt2int(ctx, v) if err != nil { return it, err } it.Page = data case "per_page": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("per_page")) data, err := ec.unmarshalNInt2int(ctx, v) if err != nil { return it, err } it.PerPage = data case "action": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("action")) data, err := ec.unmarshalOModAuditActionEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐModAuditActionEnum(ctx, v) if err != nil { return it, err } it.Action = data case "user_id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("user_id")) data, err := ec.unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.UserID = data } } return it, nil } func (ec *executionContext) unmarshalInputMoveFingerprintSubmissionsInput(ctx context.Context, obj any) (MoveFingerprintSubmissionsInput, error) { var it MoveFingerprintSubmissionsInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"fingerprints", "source_scene_id", "target_scene_id"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "fingerprints": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("fingerprints")) data, err := ec.unmarshalNFingerprintQueryInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintQueryInputᚄ(ctx, v) if err != nil { return it, err } it.Fingerprints = data case "source_scene_id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("source_scene_id")) data, err := ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.SourceSceneID = data case "target_scene_id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("target_scene_id")) data, err := ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.TargetSceneID = data } } return it, nil } func (ec *executionContext) unmarshalInputMultiIDCriterionInput(ctx context.Context, obj any) (MultiIDCriterionInput, error) { var it MultiIDCriterionInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"value", "modifier"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "value": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("value")) data, err := ec.unmarshalOID2ᚕgithubᚗcomᚋgofrsᚋuuidᚐUUIDᚄ(ctx, v) if err != nil { return it, err } it.Value = data case "modifier": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("modifier")) data, err := ec.unmarshalNCriterionModifier2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐCriterionModifier(ctx, v) if err != nil { return it, err } it.Modifier = data } } return it, nil } func (ec *executionContext) unmarshalInputMultiStringCriterionInput(ctx context.Context, obj any) (MultiStringCriterionInput, error) { var it MultiStringCriterionInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"value", "modifier"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "value": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("value")) data, err := ec.unmarshalNString2ᚕstringᚄ(ctx, v) if err != nil { return it, err } it.Value = data case "modifier": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("modifier")) data, err := ec.unmarshalNCriterionModifier2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐCriterionModifier(ctx, v) if err != nil { return it, err } it.Modifier = data } } return it, nil } func (ec *executionContext) unmarshalInputNewUserInput(ctx context.Context, obj any) (NewUserInput, error) { var it NewUserInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"email", "invite_key"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "email": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("email")) data, err := ec.unmarshalNString2string(ctx, v) if err != nil { return it, err } it.Email = data case "invite_key": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("invite_key")) data, err := ec.unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.InviteKey = data } } return it, nil } func (ec *executionContext) unmarshalInputPerformerAppearanceInput(ctx context.Context, obj any) (PerformerAppearanceInput, error) { var it PerformerAppearanceInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"performer_id", "as"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "performer_id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("performer_id")) data, err := ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.PerformerID = data case "as": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("as")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.As = data } } return it, nil } func (ec *executionContext) unmarshalInputPerformerCreateInput(ctx context.Context, obj any) (PerformerCreateInput, error) { var it PerformerCreateInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"name", "disambiguation", "aliases", "gender", "urls", "birthdate", "deathdate", "ethnicity", "country", "eye_color", "hair_color", "height", "cup_size", "band_size", "waist_size", "hip_size", "breast_type", "career_start_year", "career_end_year", "tattoos", "piercings", "image_ids", "draft_id"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "name": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) data, err := ec.unmarshalNString2string(ctx, v) if err != nil { return it, err } it.Name = data case "disambiguation": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("disambiguation")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Disambiguation = data case "aliases": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("aliases")) data, err := ec.unmarshalOString2ᚕstringᚄ(ctx, v) if err != nil { return it, err } it.Aliases = data case "gender": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("gender")) data, err := ec.unmarshalOGenderEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐGenderEnum(ctx, v) if err != nil { return it, err } it.Gender = data case "urls": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("urls")) data, err := ec.unmarshalOURLInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐURLᚄ(ctx, v) if err != nil { return it, err } it.Urls = data case "birthdate": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("birthdate")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Birthdate = data case "deathdate": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("deathdate")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Deathdate = data case "ethnicity": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("ethnicity")) data, err := ec.unmarshalOEthnicityEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEthnicityEnum(ctx, v) if err != nil { return it, err } it.Ethnicity = data case "country": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("country")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Country = data case "eye_color": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("eye_color")) data, err := ec.unmarshalOEyeColorEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEyeColorEnum(ctx, v) if err != nil { return it, err } it.EyeColor = data case "hair_color": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("hair_color")) data, err := ec.unmarshalOHairColorEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐHairColorEnum(ctx, v) if err != nil { return it, err } it.HairColor = data case "height": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("height")) data, err := ec.unmarshalOInt2ᚖint(ctx, v) if err != nil { return it, err } it.Height = data case "cup_size": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("cup_size")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.CupSize = data case "band_size": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("band_size")) data, err := ec.unmarshalOInt2ᚖint(ctx, v) if err != nil { return it, err } it.BandSize = data case "waist_size": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("waist_size")) data, err := ec.unmarshalOInt2ᚖint(ctx, v) if err != nil { return it, err } it.WaistSize = data case "hip_size": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("hip_size")) data, err := ec.unmarshalOInt2ᚖint(ctx, v) if err != nil { return it, err } it.HipSize = data case "breast_type": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("breast_type")) data, err := ec.unmarshalOBreastTypeEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐBreastTypeEnum(ctx, v) if err != nil { return it, err } it.BreastType = data case "career_start_year": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("career_start_year")) data, err := ec.unmarshalOInt2ᚖint(ctx, v) if err != nil { return it, err } it.CareerStartYear = data case "career_end_year": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("career_end_year")) data, err := ec.unmarshalOInt2ᚖint(ctx, v) if err != nil { return it, err } it.CareerEndYear = data case "tattoos": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("tattoos")) data, err := ec.unmarshalOBodyModificationInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐBodyModificationInputᚄ(ctx, v) if err != nil { return it, err } it.Tattoos = data case "piercings": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("piercings")) data, err := ec.unmarshalOBodyModificationInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐBodyModificationInputᚄ(ctx, v) if err != nil { return it, err } it.Piercings = data case "image_ids": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("image_ids")) data, err := ec.unmarshalOID2ᚕgithubᚗcomᚋgofrsᚋuuidᚐUUIDᚄ(ctx, v) if err != nil { return it, err } it.ImageIds = data case "draft_id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("draft_id")) data, err := ec.unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.DraftID = data } } return it, nil } func (ec *executionContext) unmarshalInputPerformerDestroyInput(ctx context.Context, obj any) (PerformerDestroyInput, error) { var it PerformerDestroyInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"id"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) data, err := ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.ID = data } } return it, nil } func (ec *executionContext) unmarshalInputPerformerDraftInput(ctx context.Context, obj any) (PerformerDraftInput, error) { var it PerformerDraftInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"id", "disambiguation", "name", "aliases", "gender", "birthdate", "deathdate", "urls", "ethnicity", "country", "eye_color", "hair_color", "height", "measurements", "breast_type", "tattoos", "piercings", "career_start_year", "career_end_year", "image"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) data, err := ec.unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.ID = data case "disambiguation": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("disambiguation")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Disambiguation = data case "name": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) data, err := ec.unmarshalNString2string(ctx, v) if err != nil { return it, err } it.Name = data case "aliases": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("aliases")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Aliases = data case "gender": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("gender")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Gender = data case "birthdate": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("birthdate")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Birthdate = data case "deathdate": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("deathdate")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Deathdate = data case "urls": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("urls")) data, err := ec.unmarshalOString2ᚕstringᚄ(ctx, v) if err != nil { return it, err } it.Urls = data case "ethnicity": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("ethnicity")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Ethnicity = data case "country": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("country")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Country = data case "eye_color": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("eye_color")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.EyeColor = data case "hair_color": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("hair_color")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.HairColor = data case "height": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("height")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Height = data case "measurements": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("measurements")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Measurements = data case "breast_type": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("breast_type")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.BreastType = data case "tattoos": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("tattoos")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Tattoos = data case "piercings": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("piercings")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Piercings = data case "career_start_year": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("career_start_year")) data, err := ec.unmarshalOInt2ᚖint(ctx, v) if err != nil { return it, err } it.CareerStartYear = data case "career_end_year": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("career_end_year")) data, err := ec.unmarshalOInt2ᚖint(ctx, v) if err != nil { return it, err } it.CareerEndYear = data case "image": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("image")) data, err := ec.unmarshalOUpload2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚐUpload(ctx, v) if err != nil { return it, err } it.Image = data } } return it, nil } func (ec *executionContext) unmarshalInputPerformerEditDetailsInput(ctx context.Context, obj any) (PerformerEditDetailsInput, error) { var it PerformerEditDetailsInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"name", "disambiguation", "aliases", "gender", "urls", "birthdate", "deathdate", "ethnicity", "country", "eye_color", "hair_color", "height", "cup_size", "band_size", "waist_size", "hip_size", "breast_type", "career_start_year", "career_end_year", "tattoos", "piercings", "image_ids", "draft_id"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "name": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Name = data case "disambiguation": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("disambiguation")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Disambiguation = data case "aliases": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("aliases")) data, err := ec.unmarshalOString2ᚕstringᚄ(ctx, v) if err != nil { return it, err } it.Aliases = data case "gender": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("gender")) data, err := ec.unmarshalOGenderEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐGenderEnum(ctx, v) if err != nil { return it, err } it.Gender = data case "urls": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("urls")) data, err := ec.unmarshalOURLInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐURLᚄ(ctx, v) if err != nil { return it, err } it.Urls = data case "birthdate": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("birthdate")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Birthdate = data case "deathdate": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("deathdate")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Deathdate = data case "ethnicity": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("ethnicity")) data, err := ec.unmarshalOEthnicityEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEthnicityEnum(ctx, v) if err != nil { return it, err } it.Ethnicity = data case "country": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("country")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Country = data case "eye_color": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("eye_color")) data, err := ec.unmarshalOEyeColorEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEyeColorEnum(ctx, v) if err != nil { return it, err } it.EyeColor = data case "hair_color": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("hair_color")) data, err := ec.unmarshalOHairColorEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐHairColorEnum(ctx, v) if err != nil { return it, err } it.HairColor = data case "height": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("height")) data, err := ec.unmarshalOInt2ᚖint(ctx, v) if err != nil { return it, err } it.Height = data case "cup_size": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("cup_size")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.CupSize = data case "band_size": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("band_size")) data, err := ec.unmarshalOInt2ᚖint(ctx, v) if err != nil { return it, err } it.BandSize = data case "waist_size": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("waist_size")) data, err := ec.unmarshalOInt2ᚖint(ctx, v) if err != nil { return it, err } it.WaistSize = data case "hip_size": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("hip_size")) data, err := ec.unmarshalOInt2ᚖint(ctx, v) if err != nil { return it, err } it.HipSize = data case "breast_type": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("breast_type")) data, err := ec.unmarshalOBreastTypeEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐBreastTypeEnum(ctx, v) if err != nil { return it, err } it.BreastType = data case "career_start_year": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("career_start_year")) data, err := ec.unmarshalOInt2ᚖint(ctx, v) if err != nil { return it, err } it.CareerStartYear = data case "career_end_year": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("career_end_year")) data, err := ec.unmarshalOInt2ᚖint(ctx, v) if err != nil { return it, err } it.CareerEndYear = data case "tattoos": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("tattoos")) data, err := ec.unmarshalOBodyModificationInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐBodyModificationInputᚄ(ctx, v) if err != nil { return it, err } it.Tattoos = data case "piercings": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("piercings")) data, err := ec.unmarshalOBodyModificationInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐBodyModificationInputᚄ(ctx, v) if err != nil { return it, err } it.Piercings = data case "image_ids": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("image_ids")) data, err := ec.unmarshalOID2ᚕgithubᚗcomᚋgofrsᚋuuidᚐUUIDᚄ(ctx, v) if err != nil { return it, err } it.ImageIds = data case "draft_id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("draft_id")) data, err := ec.unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.DraftID = data } } return it, nil } func (ec *executionContext) unmarshalInputPerformerEditInput(ctx context.Context, obj any) (PerformerEditInput, error) { var it PerformerEditInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"edit", "details", "options"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "edit": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("edit")) data, err := ec.unmarshalNEditInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditInput(ctx, v) if err != nil { return it, err } it.Edit = data case "details": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("details")) data, err := ec.unmarshalOPerformerEditDetailsInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerEditDetailsInput(ctx, v) if err != nil { return it, err } it.Details = data case "options": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("options")) data, err := ec.unmarshalOPerformerEditOptionsInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerEditOptionsInput(ctx, v) if err != nil { return it, err } it.Options = data } } return it, nil } func (ec *executionContext) unmarshalInputPerformerEditOptionsInput(ctx context.Context, obj any) (PerformerEditOptionsInput, error) { var it PerformerEditOptionsInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } if _, present := asMap["set_modify_aliases"]; !present { asMap["set_modify_aliases"] = false } if _, present := asMap["set_merge_aliases"]; !present { asMap["set_merge_aliases"] = true } fieldsInOrder := [...]string{"set_modify_aliases", "set_merge_aliases"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "set_modify_aliases": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("set_modify_aliases")) data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v) if err != nil { return it, err } it.SetModifyAliases = data case "set_merge_aliases": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("set_merge_aliases")) data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v) if err != nil { return it, err } it.SetMergeAliases = data } } return it, nil } func (ec *executionContext) unmarshalInputPerformerQueryInput(ctx context.Context, obj any) (PerformerQueryInput, error) { var it PerformerQueryInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } if _, present := asMap["page"]; !present { asMap["page"] = 1 } if _, present := asMap["per_page"]; !present { asMap["per_page"] = 25 } if _, present := asMap["direction"]; !present { asMap["direction"] = "DESC" } if _, present := asMap["sort"]; !present { asMap["sort"] = "CREATED_AT" } fieldsInOrder := [...]string{"names", "name", "alias", "disambiguation", "gender", "url", "birthdate", "deathdate", "birth_year", "age", "ethnicity", "country", "eye_color", "hair_color", "height", "cup_size", "band_size", "waist_size", "hip_size", "breast_type", "career_start_year", "career_end_year", "tattoos", "piercings", "is_favorite", "performed_with", "studio_id", "page", "per_page", "direction", "sort"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "names": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("names")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Names = data case "name": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Name = data case "alias": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("alias")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Alias = data case "disambiguation": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("disambiguation")) data, err := ec.unmarshalOStringCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStringCriterionInput(ctx, v) if err != nil { return it, err } it.Disambiguation = data case "gender": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("gender")) data, err := ec.unmarshalOGenderFilterEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐGenderFilterEnum(ctx, v) if err != nil { return it, err } it.Gender = data case "url": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("url")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.URL = data case "birthdate": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("birthdate")) data, err := ec.unmarshalODateCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDateCriterionInput(ctx, v) if err != nil { return it, err } it.Birthdate = data case "deathdate": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("deathdate")) data, err := ec.unmarshalODateCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDateCriterionInput(ctx, v) if err != nil { return it, err } it.Deathdate = data case "birth_year": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("birth_year")) data, err := ec.unmarshalOIntCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐIntCriterionInput(ctx, v) if err != nil { return it, err } it.BirthYear = data case "age": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("age")) data, err := ec.unmarshalOIntCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐIntCriterionInput(ctx, v) if err != nil { return it, err } it.Age = data case "ethnicity": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("ethnicity")) data, err := ec.unmarshalOEthnicityFilterEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEthnicityFilterEnum(ctx, v) if err != nil { return it, err } it.Ethnicity = data case "country": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("country")) data, err := ec.unmarshalOStringCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStringCriterionInput(ctx, v) if err != nil { return it, err } it.Country = data case "eye_color": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("eye_color")) data, err := ec.unmarshalOEyeColorCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEyeColorCriterionInput(ctx, v) if err != nil { return it, err } it.EyeColor = data case "hair_color": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("hair_color")) data, err := ec.unmarshalOHairColorCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐHairColorCriterionInput(ctx, v) if err != nil { return it, err } it.HairColor = data case "height": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("height")) data, err := ec.unmarshalOIntCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐIntCriterionInput(ctx, v) if err != nil { return it, err } it.Height = data case "cup_size": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("cup_size")) data, err := ec.unmarshalOStringCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStringCriterionInput(ctx, v) if err != nil { return it, err } it.CupSize = data case "band_size": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("band_size")) data, err := ec.unmarshalOIntCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐIntCriterionInput(ctx, v) if err != nil { return it, err } it.BandSize = data case "waist_size": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("waist_size")) data, err := ec.unmarshalOIntCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐIntCriterionInput(ctx, v) if err != nil { return it, err } it.WaistSize = data case "hip_size": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("hip_size")) data, err := ec.unmarshalOIntCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐIntCriterionInput(ctx, v) if err != nil { return it, err } it.HipSize = data case "breast_type": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("breast_type")) data, err := ec.unmarshalOBreastTypeCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐBreastTypeCriterionInput(ctx, v) if err != nil { return it, err } it.BreastType = data case "career_start_year": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("career_start_year")) data, err := ec.unmarshalOIntCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐIntCriterionInput(ctx, v) if err != nil { return it, err } it.CareerStartYear = data case "career_end_year": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("career_end_year")) data, err := ec.unmarshalOIntCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐIntCriterionInput(ctx, v) if err != nil { return it, err } it.CareerEndYear = data case "tattoos": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("tattoos")) data, err := ec.unmarshalOBodyModificationCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐBodyModificationCriterionInput(ctx, v) if err != nil { return it, err } it.Tattoos = data case "piercings": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("piercings")) data, err := ec.unmarshalOBodyModificationCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐBodyModificationCriterionInput(ctx, v) if err != nil { return it, err } it.Piercings = data case "is_favorite": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("is_favorite")) data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v) if err != nil { return it, err } it.IsFavorite = data case "performed_with": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("performed_with")) data, err := ec.unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.PerformedWith = data case "studio_id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("studio_id")) data, err := ec.unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.StudioID = data case "page": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("page")) data, err := ec.unmarshalNInt2int(ctx, v) if err != nil { return it, err } it.Page = data case "per_page": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("per_page")) data, err := ec.unmarshalNInt2int(ctx, v) if err != nil { return it, err } it.PerPage = data case "direction": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("direction")) data, err := ec.unmarshalNSortDirectionEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSortDirectionEnum(ctx, v) if err != nil { return it, err } it.Direction = data case "sort": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("sort")) data, err := ec.unmarshalNPerformerSortEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerSortEnum(ctx, v) if err != nil { return it, err } it.Sort = data } } return it, nil } func (ec *executionContext) unmarshalInputPerformerScenesInput(ctx context.Context, obj any) (PerformerScenesInput, error) { var it PerformerScenesInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"performed_with", "studio_id", "tags"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "performed_with": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("performed_with")) data, err := ec.unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.PerformedWith = data case "studio_id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("studio_id")) data, err := ec.unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.StudioID = data case "tags": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("tags")) data, err := ec.unmarshalOMultiIDCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐMultiIDCriterionInput(ctx, v) if err != nil { return it, err } it.Tags = data } } return it, nil } func (ec *executionContext) unmarshalInputPerformerSearchFilter(ctx context.Context, obj any) (PerformerSearchFilter, error) { var it PerformerSearchFilter if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"gender"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "gender": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("gender")) data, err := ec.unmarshalOGenderEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐGenderEnum(ctx, v) if err != nil { return it, err } it.Gender = data } } return it, nil } func (ec *executionContext) unmarshalInputPerformerUpdateInput(ctx context.Context, obj any) (PerformerUpdateInput, error) { var it PerformerUpdateInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"id", "name", "disambiguation", "aliases", "gender", "urls", "birthdate", "deathdate", "ethnicity", "country", "eye_color", "hair_color", "height", "cup_size", "band_size", "waist_size", "hip_size", "breast_type", "career_start_year", "career_end_year", "tattoos", "piercings", "image_ids"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) data, err := ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.ID = data case "name": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Name = data case "disambiguation": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("disambiguation")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Disambiguation = data case "aliases": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("aliases")) data, err := ec.unmarshalOString2ᚕstringᚄ(ctx, v) if err != nil { return it, err } it.Aliases = data case "gender": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("gender")) data, err := ec.unmarshalOGenderEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐGenderEnum(ctx, v) if err != nil { return it, err } it.Gender = data case "urls": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("urls")) data, err := ec.unmarshalOURLInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐURLᚄ(ctx, v) if err != nil { return it, err } it.Urls = data case "birthdate": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("birthdate")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Birthdate = data case "deathdate": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("deathdate")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Deathdate = data case "ethnicity": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("ethnicity")) data, err := ec.unmarshalOEthnicityEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEthnicityEnum(ctx, v) if err != nil { return it, err } it.Ethnicity = data case "country": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("country")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Country = data case "eye_color": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("eye_color")) data, err := ec.unmarshalOEyeColorEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEyeColorEnum(ctx, v) if err != nil { return it, err } it.EyeColor = data case "hair_color": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("hair_color")) data, err := ec.unmarshalOHairColorEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐHairColorEnum(ctx, v) if err != nil { return it, err } it.HairColor = data case "height": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("height")) data, err := ec.unmarshalOInt2ᚖint(ctx, v) if err != nil { return it, err } it.Height = data case "cup_size": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("cup_size")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.CupSize = data case "band_size": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("band_size")) data, err := ec.unmarshalOInt2ᚖint(ctx, v) if err != nil { return it, err } it.BandSize = data case "waist_size": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("waist_size")) data, err := ec.unmarshalOInt2ᚖint(ctx, v) if err != nil { return it, err } it.WaistSize = data case "hip_size": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("hip_size")) data, err := ec.unmarshalOInt2ᚖint(ctx, v) if err != nil { return it, err } it.HipSize = data case "breast_type": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("breast_type")) data, err := ec.unmarshalOBreastTypeEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐBreastTypeEnum(ctx, v) if err != nil { return it, err } it.BreastType = data case "career_start_year": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("career_start_year")) data, err := ec.unmarshalOInt2ᚖint(ctx, v) if err != nil { return it, err } it.CareerStartYear = data case "career_end_year": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("career_end_year")) data, err := ec.unmarshalOInt2ᚖint(ctx, v) if err != nil { return it, err } it.CareerEndYear = data case "tattoos": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("tattoos")) data, err := ec.unmarshalOBodyModificationInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐBodyModificationInputᚄ(ctx, v) if err != nil { return it, err } it.Tattoos = data case "piercings": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("piercings")) data, err := ec.unmarshalOBodyModificationInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐBodyModificationInputᚄ(ctx, v) if err != nil { return it, err } it.Piercings = data case "image_ids": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("image_ids")) data, err := ec.unmarshalOID2ᚕgithubᚗcomᚋgofrsᚋuuidᚐUUIDᚄ(ctx, v) if err != nil { return it, err } it.ImageIds = data } } return it, nil } func (ec *executionContext) unmarshalInputQueryExistingPerformerInput(ctx context.Context, obj any) (QueryExistingPerformerInput, error) { var it QueryExistingPerformerInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"name", "disambiguation", "urls"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "name": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Name = data case "disambiguation": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("disambiguation")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Disambiguation = data case "urls": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("urls")) data, err := ec.unmarshalNString2ᚕstringᚄ(ctx, v) if err != nil { return it, err } it.Urls = data } } return it, nil } func (ec *executionContext) unmarshalInputQueryExistingSceneInput(ctx context.Context, obj any) (QueryExistingSceneInput, error) { var it QueryExistingSceneInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"title", "studio_id", "fingerprints"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "title": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("title")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Title = data case "studio_id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("studio_id")) data, err := ec.unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.StudioID = data case "fingerprints": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("fingerprints")) data, err := ec.unmarshalNFingerprintInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintInputᚄ(ctx, v) if err != nil { return it, err } it.Fingerprints = data } } return it, nil } func (ec *executionContext) unmarshalInputQueryNotificationsInput(ctx context.Context, obj any) (QueryNotificationsInput, error) { var it QueryNotificationsInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } if _, present := asMap["page"]; !present { asMap["page"] = 1 } if _, present := asMap["per_page"]; !present { asMap["per_page"] = 25 } fieldsInOrder := [...]string{"page", "per_page", "type", "unread_only"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "page": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("page")) data, err := ec.unmarshalNInt2int(ctx, v) if err != nil { return it, err } it.Page = data case "per_page": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("per_page")) data, err := ec.unmarshalNInt2int(ctx, v) if err != nil { return it, err } it.PerPage = data case "type": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("type")) data, err := ec.unmarshalONotificationEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐNotificationEnum(ctx, v) if err != nil { return it, err } it.Type = data case "unread_only": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("unread_only")) data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v) if err != nil { return it, err } it.UnreadOnly = data } } return it, nil } func (ec *executionContext) unmarshalInputResetPasswordInput(ctx context.Context, obj any) (ResetPasswordInput, error) { var it ResetPasswordInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"email"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "email": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("email")) data, err := ec.unmarshalNString2string(ctx, v) if err != nil { return it, err } it.Email = data } } return it, nil } func (ec *executionContext) unmarshalInputRevokeInviteInput(ctx context.Context, obj any) (RevokeInviteInput, error) { var it RevokeInviteInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"user_id", "amount"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "user_id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("user_id")) data, err := ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.UserID = data case "amount": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("amount")) data, err := ec.unmarshalNInt2int(ctx, v) if err != nil { return it, err } it.Amount = data } } return it, nil } func (ec *executionContext) unmarshalInputRoleCriterionInput(ctx context.Context, obj any) (RoleCriterionInput, error) { var it RoleCriterionInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"value", "modifier"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "value": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("value")) data, err := ec.unmarshalNRoleEnum2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnumᚄ(ctx, v) if err != nil { return it, err } it.Value = data case "modifier": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("modifier")) data, err := ec.unmarshalNCriterionModifier2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐCriterionModifier(ctx, v) if err != nil { return it, err } it.Modifier = data } } return it, nil } func (ec *executionContext) unmarshalInputSceneCreateInput(ctx context.Context, obj any) (SceneCreateInput, error) { var it SceneCreateInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"title", "details", "urls", "date", "production_date", "studio_id", "performers", "tag_ids", "image_ids", "fingerprints", "duration", "director", "code"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "title": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("title")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Title = data case "details": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("details")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Details = data case "urls": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("urls")) data, err := ec.unmarshalOURLInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐURLᚄ(ctx, v) if err != nil { return it, err } it.Urls = data case "date": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("date")) data, err := ec.unmarshalNString2string(ctx, v) if err != nil { return it, err } it.Date = data case "production_date": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("production_date")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.ProductionDate = data case "studio_id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("studio_id")) data, err := ec.unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.StudioID = data case "performers": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("performers")) data, err := ec.unmarshalOPerformerAppearanceInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerAppearanceInputᚄ(ctx, v) if err != nil { return it, err } it.Performers = data case "tag_ids": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("tag_ids")) data, err := ec.unmarshalOID2ᚕgithubᚗcomᚋgofrsᚋuuidᚐUUIDᚄ(ctx, v) if err != nil { return it, err } it.TagIds = data case "image_ids": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("image_ids")) data, err := ec.unmarshalOID2ᚕgithubᚗcomᚋgofrsᚋuuidᚐUUIDᚄ(ctx, v) if err != nil { return it, err } it.ImageIds = data case "fingerprints": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("fingerprints")) data, err := ec.unmarshalNFingerprintEditInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintEditInputᚄ(ctx, v) if err != nil { return it, err } it.Fingerprints = data case "duration": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("duration")) data, err := ec.unmarshalOInt2ᚖint(ctx, v) if err != nil { return it, err } it.Duration = data case "director": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("director")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Director = data case "code": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("code")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Code = data } } return it, nil } func (ec *executionContext) unmarshalInputSceneDestroyInput(ctx context.Context, obj any) (SceneDestroyInput, error) { var it SceneDestroyInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"id"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) data, err := ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.ID = data } } return it, nil } func (ec *executionContext) unmarshalInputSceneDraftInput(ctx context.Context, obj any) (SceneDraftInput, error) { var it SceneDraftInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"id", "title", "code", "details", "director", "url", "urls", "date", "production_date", "studio", "performers", "tags", "image", "fingerprints"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) data, err := ec.unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.ID = data case "title": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("title")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Title = data case "code": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("code")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Code = data case "details": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("details")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Details = data case "director": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("director")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Director = data case "url": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("url")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.URL = data case "urls": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("urls")) data, err := ec.unmarshalOString2ᚕstringᚄ(ctx, v) if err != nil { return it, err } it.Urls = data case "date": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("date")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Date = data case "production_date": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("production_date")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.ProductionDate = data case "studio": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("studio")) data, err := ec.unmarshalODraftEntityInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDraftEntityInput(ctx, v) if err != nil { return it, err } it.Studio = data case "performers": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("performers")) data, err := ec.unmarshalNDraftEntityInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDraftEntityInputᚄ(ctx, v) if err != nil { return it, err } it.Performers = data case "tags": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("tags")) data, err := ec.unmarshalODraftEntityInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDraftEntityInputᚄ(ctx, v) if err != nil { return it, err } it.Tags = data case "image": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("image")) data, err := ec.unmarshalOUpload2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚐUpload(ctx, v) if err != nil { return it, err } it.Image = data case "fingerprints": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("fingerprints")) data, err := ec.unmarshalNFingerprintInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintInputᚄ(ctx, v) if err != nil { return it, err } it.Fingerprints = data } } return it, nil } func (ec *executionContext) unmarshalInputSceneEditDetailsInput(ctx context.Context, obj any) (SceneEditDetailsInput, error) { var it SceneEditDetailsInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"title", "details", "urls", "date", "production_date", "studio_id", "performers", "tag_ids", "image_ids", "duration", "director", "code", "fingerprints", "draft_id"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "title": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("title")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Title = data case "details": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("details")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Details = data case "urls": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("urls")) data, err := ec.unmarshalOURLInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐURLᚄ(ctx, v) if err != nil { return it, err } it.Urls = data case "date": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("date")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Date = data case "production_date": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("production_date")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.ProductionDate = data case "studio_id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("studio_id")) data, err := ec.unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.StudioID = data case "performers": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("performers")) data, err := ec.unmarshalOPerformerAppearanceInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerAppearanceInputᚄ(ctx, v) if err != nil { return it, err } it.Performers = data case "tag_ids": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("tag_ids")) data, err := ec.unmarshalOID2ᚕgithubᚗcomᚋgofrsᚋuuidᚐUUIDᚄ(ctx, v) if err != nil { return it, err } it.TagIds = data case "image_ids": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("image_ids")) data, err := ec.unmarshalOID2ᚕgithubᚗcomᚋgofrsᚋuuidᚐUUIDᚄ(ctx, v) if err != nil { return it, err } it.ImageIds = data case "duration": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("duration")) data, err := ec.unmarshalOInt2ᚖint(ctx, v) if err != nil { return it, err } it.Duration = data case "director": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("director")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Director = data case "code": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("code")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Code = data case "fingerprints": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("fingerprints")) data, err := ec.unmarshalOFingerprintInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintInputᚄ(ctx, v) if err != nil { return it, err } it.Fingerprints = data case "draft_id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("draft_id")) data, err := ec.unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.DraftID = data } } return it, nil } func (ec *executionContext) unmarshalInputSceneEditInput(ctx context.Context, obj any) (SceneEditInput, error) { var it SceneEditInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"edit", "details"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "edit": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("edit")) data, err := ec.unmarshalNEditInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditInput(ctx, v) if err != nil { return it, err } it.Edit = data case "details": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("details")) data, err := ec.unmarshalOSceneEditDetailsInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneEditDetailsInput(ctx, v) if err != nil { return it, err } it.Details = data } } return it, nil } func (ec *executionContext) unmarshalInputSceneQueryInput(ctx context.Context, obj any) (SceneQueryInput, error) { var it SceneQueryInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } if _, present := asMap["has_fingerprint_submissions"]; !present { asMap["has_fingerprint_submissions"] = "False" } if _, present := asMap["page"]; !present { asMap["page"] = 1 } if _, present := asMap["per_page"]; !present { asMap["per_page"] = 25 } if _, present := asMap["direction"]; !present { asMap["direction"] = "DESC" } if _, present := asMap["sort"]; !present { asMap["sort"] = "DATE" } fieldsInOrder := [...]string{"text", "title", "url", "date", "production_date", "studios", "parentStudio", "tags", "performers", "alias", "fingerprints", "favorites", "has_fingerprint_submissions", "page", "per_page", "direction", "sort"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "text": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("text")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Text = data case "title": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("title")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Title = data case "url": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("url")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.URL = data case "date": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("date")) data, err := ec.unmarshalODateCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDateCriterionInput(ctx, v) if err != nil { return it, err } it.Date = data case "production_date": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("production_date")) data, err := ec.unmarshalODateCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDateCriterionInput(ctx, v) if err != nil { return it, err } it.ProductionDate = data case "studios": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("studios")) data, err := ec.unmarshalOMultiIDCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐMultiIDCriterionInput(ctx, v) if err != nil { return it, err } it.Studios = data case "parentStudio": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("parentStudio")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.ParentStudio = data case "tags": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("tags")) data, err := ec.unmarshalOMultiIDCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐMultiIDCriterionInput(ctx, v) if err != nil { return it, err } it.Tags = data case "performers": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("performers")) data, err := ec.unmarshalOMultiIDCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐMultiIDCriterionInput(ctx, v) if err != nil { return it, err } it.Performers = data case "alias": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("alias")) data, err := ec.unmarshalOStringCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStringCriterionInput(ctx, v) if err != nil { return it, err } it.Alias = data case "fingerprints": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("fingerprints")) data, err := ec.unmarshalOMultiStringCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐMultiStringCriterionInput(ctx, v) if err != nil { return it, err } it.Fingerprints = data case "favorites": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("favorites")) data, err := ec.unmarshalOFavoriteFilter2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFavoriteFilter(ctx, v) if err != nil { return it, err } it.Favorites = data case "has_fingerprint_submissions": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("has_fingerprint_submissions")) data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v) if err != nil { return it, err } it.HasFingerprintSubmissions = data case "page": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("page")) data, err := ec.unmarshalNInt2int(ctx, v) if err != nil { return it, err } it.Page = data case "per_page": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("per_page")) data, err := ec.unmarshalNInt2int(ctx, v) if err != nil { return it, err } it.PerPage = data case "direction": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("direction")) data, err := ec.unmarshalNSortDirectionEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSortDirectionEnum(ctx, v) if err != nil { return it, err } it.Direction = data case "sort": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("sort")) data, err := ec.unmarshalNSceneSortEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneSortEnum(ctx, v) if err != nil { return it, err } it.Sort = data } } return it, nil } func (ec *executionContext) unmarshalInputSceneUpdateInput(ctx context.Context, obj any) (SceneUpdateInput, error) { var it SceneUpdateInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"id", "title", "details", "urls", "date", "production_date", "studio_id", "performers", "tag_ids", "image_ids", "fingerprints", "duration", "director", "code"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) data, err := ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.ID = data case "title": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("title")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Title = data case "details": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("details")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Details = data case "urls": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("urls")) data, err := ec.unmarshalOURLInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐURLᚄ(ctx, v) if err != nil { return it, err } it.Urls = data case "date": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("date")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Date = data case "production_date": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("production_date")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.ProductionDate = data case "studio_id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("studio_id")) data, err := ec.unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.StudioID = data case "performers": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("performers")) data, err := ec.unmarshalOPerformerAppearanceInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerAppearanceInputᚄ(ctx, v) if err != nil { return it, err } it.Performers = data case "tag_ids": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("tag_ids")) data, err := ec.unmarshalOID2ᚕgithubᚗcomᚋgofrsᚋuuidᚐUUIDᚄ(ctx, v) if err != nil { return it, err } it.TagIds = data case "image_ids": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("image_ids")) data, err := ec.unmarshalOID2ᚕgithubᚗcomᚋgofrsᚋuuidᚐUUIDᚄ(ctx, v) if err != nil { return it, err } it.ImageIds = data case "fingerprints": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("fingerprints")) data, err := ec.unmarshalOFingerprintEditInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintEditInputᚄ(ctx, v) if err != nil { return it, err } it.Fingerprints = data case "duration": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("duration")) data, err := ec.unmarshalOInt2ᚖint(ctx, v) if err != nil { return it, err } it.Duration = data case "director": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("director")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Director = data case "code": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("code")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Code = data } } return it, nil } func (ec *executionContext) unmarshalInputSiteCreateInput(ctx context.Context, obj any) (SiteCreateInput, error) { var it SiteCreateInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"name", "description", "url", "regex", "valid_types"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "name": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) data, err := ec.unmarshalNString2string(ctx, v) if err != nil { return it, err } it.Name = data case "description": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("description")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Description = data case "url": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("url")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.URL = data case "regex": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("regex")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Regex = data case "valid_types": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("valid_types")) data, err := ec.unmarshalNValidSiteTypeEnum2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐValidSiteTypeEnumᚄ(ctx, v) if err != nil { return it, err } it.ValidTypes = data } } return it, nil } func (ec *executionContext) unmarshalInputSiteDestroyInput(ctx context.Context, obj any) (SiteDestroyInput, error) { var it SiteDestroyInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"id"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) data, err := ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.ID = data } } return it, nil } func (ec *executionContext) unmarshalInputSiteUpdateInput(ctx context.Context, obj any) (SiteUpdateInput, error) { var it SiteUpdateInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"id", "name", "description", "url", "regex", "valid_types"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) data, err := ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.ID = data case "name": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) data, err := ec.unmarshalNString2string(ctx, v) if err != nil { return it, err } it.Name = data case "description": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("description")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Description = data case "url": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("url")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.URL = data case "regex": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("regex")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Regex = data case "valid_types": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("valid_types")) data, err := ec.unmarshalNValidSiteTypeEnum2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐValidSiteTypeEnumᚄ(ctx, v) if err != nil { return it, err } it.ValidTypes = data } } return it, nil } func (ec *executionContext) unmarshalInputStringCriterionInput(ctx context.Context, obj any) (StringCriterionInput, error) { var it StringCriterionInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"value", "modifier"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "value": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("value")) data, err := ec.unmarshalNString2string(ctx, v) if err != nil { return it, err } it.Value = data case "modifier": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("modifier")) data, err := ec.unmarshalNCriterionModifier2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐCriterionModifier(ctx, v) if err != nil { return it, err } it.Modifier = data } } return it, nil } func (ec *executionContext) unmarshalInputStudioCreateInput(ctx context.Context, obj any) (StudioCreateInput, error) { var it StudioCreateInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"name", "aliases", "urls", "parent_id", "image_ids"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "name": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) data, err := ec.unmarshalNString2string(ctx, v) if err != nil { return it, err } it.Name = data case "aliases": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("aliases")) data, err := ec.unmarshalOString2ᚕstringᚄ(ctx, v) if err != nil { return it, err } it.Aliases = data case "urls": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("urls")) data, err := ec.unmarshalOURLInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐURLᚄ(ctx, v) if err != nil { return it, err } it.Urls = data case "parent_id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("parent_id")) data, err := ec.unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.ParentID = data case "image_ids": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("image_ids")) data, err := ec.unmarshalOID2ᚕgithubᚗcomᚋgofrsᚋuuidᚐUUIDᚄ(ctx, v) if err != nil { return it, err } it.ImageIds = data } } return it, nil } func (ec *executionContext) unmarshalInputStudioDestroyInput(ctx context.Context, obj any) (StudioDestroyInput, error) { var it StudioDestroyInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"id"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) data, err := ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.ID = data } } return it, nil } func (ec *executionContext) unmarshalInputStudioEditDetailsInput(ctx context.Context, obj any) (StudioEditDetailsInput, error) { var it StudioEditDetailsInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"name", "aliases", "urls", "parent_id", "image_ids"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "name": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Name = data case "aliases": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("aliases")) data, err := ec.unmarshalOString2ᚕstringᚄ(ctx, v) if err != nil { return it, err } it.Aliases = data case "urls": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("urls")) data, err := ec.unmarshalOURLInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐURLᚄ(ctx, v) if err != nil { return it, err } it.Urls = data case "parent_id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("parent_id")) data, err := ec.unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.ParentID = data case "image_ids": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("image_ids")) data, err := ec.unmarshalOID2ᚕgithubᚗcomᚋgofrsᚋuuidᚐUUIDᚄ(ctx, v) if err != nil { return it, err } it.ImageIds = data } } return it, nil } func (ec *executionContext) unmarshalInputStudioEditInput(ctx context.Context, obj any) (StudioEditInput, error) { var it StudioEditInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"edit", "details"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "edit": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("edit")) data, err := ec.unmarshalNEditInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditInput(ctx, v) if err != nil { return it, err } it.Edit = data case "details": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("details")) data, err := ec.unmarshalOStudioEditDetailsInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStudioEditDetailsInput(ctx, v) if err != nil { return it, err } it.Details = data } } return it, nil } func (ec *executionContext) unmarshalInputStudioQueryInput(ctx context.Context, obj any) (StudioQueryInput, error) { var it StudioQueryInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } if _, present := asMap["page"]; !present { asMap["page"] = 1 } if _, present := asMap["per_page"]; !present { asMap["per_page"] = 25 } if _, present := asMap["direction"]; !present { asMap["direction"] = "ASC" } if _, present := asMap["sort"]; !present { asMap["sort"] = "NAME" } fieldsInOrder := [...]string{"name", "names", "url", "parent", "has_parent", "is_favorite", "page", "per_page", "direction", "sort"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "name": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Name = data case "names": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("names")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Names = data case "url": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("url")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.URL = data case "parent": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("parent")) data, err := ec.unmarshalOIDCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐIDCriterionInput(ctx, v) if err != nil { return it, err } it.Parent = data case "has_parent": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("has_parent")) data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v) if err != nil { return it, err } it.HasParent = data case "is_favorite": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("is_favorite")) data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v) if err != nil { return it, err } it.IsFavorite = data case "page": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("page")) data, err := ec.unmarshalNInt2int(ctx, v) if err != nil { return it, err } it.Page = data case "per_page": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("per_page")) data, err := ec.unmarshalNInt2int(ctx, v) if err != nil { return it, err } it.PerPage = data case "direction": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("direction")) data, err := ec.unmarshalNSortDirectionEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSortDirectionEnum(ctx, v) if err != nil { return it, err } it.Direction = data case "sort": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("sort")) data, err := ec.unmarshalNStudioSortEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStudioSortEnum(ctx, v) if err != nil { return it, err } it.Sort = data } } return it, nil } func (ec *executionContext) unmarshalInputStudioUpdateInput(ctx context.Context, obj any) (StudioUpdateInput, error) { var it StudioUpdateInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"id", "name", "aliases", "urls", "parent_id", "image_ids"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) data, err := ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.ID = data case "name": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Name = data case "aliases": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("aliases")) data, err := ec.unmarshalOString2ᚕstringᚄ(ctx, v) if err != nil { return it, err } it.Aliases = data case "urls": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("urls")) data, err := ec.unmarshalOURLInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐURLᚄ(ctx, v) if err != nil { return it, err } it.Urls = data case "parent_id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("parent_id")) data, err := ec.unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.ParentID = data case "image_ids": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("image_ids")) data, err := ec.unmarshalOID2ᚕgithubᚗcomᚋgofrsᚋuuidᚐUUIDᚄ(ctx, v) if err != nil { return it, err } it.ImageIds = data } } return it, nil } func (ec *executionContext) unmarshalInputTagCategoryCreateInput(ctx context.Context, obj any) (TagCategoryCreateInput, error) { var it TagCategoryCreateInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"name", "group", "description"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "name": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) data, err := ec.unmarshalNString2string(ctx, v) if err != nil { return it, err } it.Name = data case "group": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("group")) data, err := ec.unmarshalNTagGroupEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagGroupEnum(ctx, v) if err != nil { return it, err } it.Group = data case "description": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("description")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Description = data } } return it, nil } func (ec *executionContext) unmarshalInputTagCategoryDestroyInput(ctx context.Context, obj any) (TagCategoryDestroyInput, error) { var it TagCategoryDestroyInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"id"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) data, err := ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.ID = data } } return it, nil } func (ec *executionContext) unmarshalInputTagCategoryUpdateInput(ctx context.Context, obj any) (TagCategoryUpdateInput, error) { var it TagCategoryUpdateInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"id", "name", "group", "description"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) data, err := ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.ID = data case "name": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Name = data case "group": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("group")) data, err := ec.unmarshalOTagGroupEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagGroupEnum(ctx, v) if err != nil { return it, err } it.Group = data case "description": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("description")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Description = data } } return it, nil } func (ec *executionContext) unmarshalInputTagCreateInput(ctx context.Context, obj any) (TagCreateInput, error) { var it TagCreateInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"name", "description", "aliases", "category_id"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "name": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) data, err := ec.unmarshalNString2string(ctx, v) if err != nil { return it, err } it.Name = data case "description": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("description")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Description = data case "aliases": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("aliases")) data, err := ec.unmarshalOString2ᚕstringᚄ(ctx, v) if err != nil { return it, err } it.Aliases = data case "category_id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("category_id")) data, err := ec.unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.CategoryID = data } } return it, nil } func (ec *executionContext) unmarshalInputTagDestroyInput(ctx context.Context, obj any) (TagDestroyInput, error) { var it TagDestroyInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"id"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) data, err := ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.ID = data } } return it, nil } func (ec *executionContext) unmarshalInputTagEditDetailsInput(ctx context.Context, obj any) (TagEditDetailsInput, error) { var it TagEditDetailsInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"name", "description", "aliases", "category_id"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "name": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Name = data case "description": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("description")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Description = data case "aliases": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("aliases")) data, err := ec.unmarshalOString2ᚕstringᚄ(ctx, v) if err != nil { return it, err } it.Aliases = data case "category_id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("category_id")) data, err := ec.unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.CategoryID = data } } return it, nil } func (ec *executionContext) unmarshalInputTagEditInput(ctx context.Context, obj any) (TagEditInput, error) { var it TagEditInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"edit", "details"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "edit": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("edit")) data, err := ec.unmarshalNEditInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditInput(ctx, v) if err != nil { return it, err } it.Edit = data case "details": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("details")) data, err := ec.unmarshalOTagEditDetailsInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagEditDetailsInput(ctx, v) if err != nil { return it, err } it.Details = data } } return it, nil } func (ec *executionContext) unmarshalInputTagQueryInput(ctx context.Context, obj any) (TagQueryInput, error) { var it TagQueryInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } if _, present := asMap["page"]; !present { asMap["page"] = 1 } if _, present := asMap["per_page"]; !present { asMap["per_page"] = 25 } if _, present := asMap["direction"]; !present { asMap["direction"] = "ASC" } if _, present := asMap["sort"]; !present { asMap["sort"] = "NAME" } fieldsInOrder := [...]string{"text", "names", "name", "category_id", "page", "per_page", "direction", "sort"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "text": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("text")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Text = data case "names": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("names")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Names = data case "name": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Name = data case "category_id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("category_id")) data, err := ec.unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.CategoryID = data case "page": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("page")) data, err := ec.unmarshalNInt2int(ctx, v) if err != nil { return it, err } it.Page = data case "per_page": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("per_page")) data, err := ec.unmarshalNInt2int(ctx, v) if err != nil { return it, err } it.PerPage = data case "direction": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("direction")) data, err := ec.unmarshalNSortDirectionEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSortDirectionEnum(ctx, v) if err != nil { return it, err } it.Direction = data case "sort": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("sort")) data, err := ec.unmarshalNTagSortEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagSortEnum(ctx, v) if err != nil { return it, err } it.Sort = data } } return it, nil } func (ec *executionContext) unmarshalInputTagUpdateInput(ctx context.Context, obj any) (TagUpdateInput, error) { var it TagUpdateInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"id", "name", "description", "aliases", "category_id"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) data, err := ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.ID = data case "name": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Name = data case "description": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("description")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Description = data case "aliases": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("aliases")) data, err := ec.unmarshalOString2ᚕstringᚄ(ctx, v) if err != nil { return it, err } it.Aliases = data case "category_id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("category_id")) data, err := ec.unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.CategoryID = data } } return it, nil } func (ec *executionContext) unmarshalInputURLInput(ctx context.Context, obj any) (URL, error) { var it URL if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"url", "site_id"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "url": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("url")) data, err := ec.unmarshalNString2string(ctx, v) if err != nil { return it, err } it.URL = data case "site_id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("site_id")) data, err := ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.SiteID = data } } return it, nil } func (ec *executionContext) unmarshalInputUserChangeEmailInput(ctx context.Context, obj any) (UserChangeEmailInput, error) { var it UserChangeEmailInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"existing_email_token", "new_email_token", "new_email"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "existing_email_token": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("existing_email_token")) data, err := ec.unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.ExistingEmailToken = data case "new_email_token": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("new_email_token")) data, err := ec.unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.NewEmailToken = data case "new_email": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("new_email")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.NewEmail = data } } return it, nil } func (ec *executionContext) unmarshalInputUserChangePasswordInput(ctx context.Context, obj any) (UserChangePasswordInput, error) { var it UserChangePasswordInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"existing_password", "new_password", "reset_key"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "existing_password": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("existing_password")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.ExistingPassword = data case "new_password": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("new_password")) data, err := ec.unmarshalNString2string(ctx, v) if err != nil { return it, err } it.NewPassword = data case "reset_key": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("reset_key")) data, err := ec.unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.ResetKey = data } } return it, nil } func (ec *executionContext) unmarshalInputUserCreateInput(ctx context.Context, obj any) (UserCreateInput, error) { var it UserCreateInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"name", "password", "roles", "email", "invited_by_id"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "name": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) data, err := ec.unmarshalNString2string(ctx, v) if err != nil { return it, err } it.Name = data case "password": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("password")) data, err := ec.unmarshalNString2string(ctx, v) if err != nil { return it, err } it.Password = data case "roles": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("roles")) data, err := ec.unmarshalNRoleEnum2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnumᚄ(ctx, v) if err != nil { return it, err } it.Roles = data case "email": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("email")) data, err := ec.unmarshalNString2string(ctx, v) if err != nil { return it, err } it.Email = data case "invited_by_id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("invited_by_id")) data, err := ec.unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.InvitedByID = data } } return it, nil } func (ec *executionContext) unmarshalInputUserDestroyInput(ctx context.Context, obj any) (UserDestroyInput, error) { var it UserDestroyInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"id"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) data, err := ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.ID = data } } return it, nil } func (ec *executionContext) unmarshalInputUserQueryInput(ctx context.Context, obj any) (UserQueryInput, error) { var it UserQueryInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } if _, present := asMap["page"]; !present { asMap["page"] = 1 } if _, present := asMap["per_page"]; !present { asMap["per_page"] = 25 } fieldsInOrder := [...]string{"name", "email", "roles", "apiKey", "successful_edits", "unsuccessful_edits", "successful_votes", "unsuccessful_votes", "api_calls", "invited_by", "page", "per_page"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "name": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Name = data case "email": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("email")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Email = data case "roles": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("roles")) data, err := ec.unmarshalORoleCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleCriterionInput(ctx, v) if err != nil { return it, err } it.Roles = data case "apiKey": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("apiKey")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.APIKey = data case "successful_edits": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("successful_edits")) data, err := ec.unmarshalOIntCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐIntCriterionInput(ctx, v) if err != nil { return it, err } it.SuccessfulEdits = data case "unsuccessful_edits": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("unsuccessful_edits")) data, err := ec.unmarshalOIntCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐIntCriterionInput(ctx, v) if err != nil { return it, err } it.UnsuccessfulEdits = data case "successful_votes": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("successful_votes")) data, err := ec.unmarshalOIntCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐIntCriterionInput(ctx, v) if err != nil { return it, err } it.SuccessfulVotes = data case "unsuccessful_votes": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("unsuccessful_votes")) data, err := ec.unmarshalOIntCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐIntCriterionInput(ctx, v) if err != nil { return it, err } it.UnsuccessfulVotes = data case "api_calls": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("api_calls")) data, err := ec.unmarshalOIntCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐIntCriterionInput(ctx, v) if err != nil { return it, err } it.APICalls = data case "invited_by": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("invited_by")) data, err := ec.unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.InvitedBy = data case "page": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("page")) data, err := ec.unmarshalNInt2int(ctx, v) if err != nil { return it, err } it.Page = data case "per_page": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("per_page")) data, err := ec.unmarshalNInt2int(ctx, v) if err != nil { return it, err } it.PerPage = data } } return it, nil } func (ec *executionContext) unmarshalInputUserUpdateInput(ctx context.Context, obj any) (UserUpdateInput, error) { var it UserUpdateInput if obj == nil { return it, nil } asMap := map[string]any{} for k, v := range obj.(map[string]any) { asMap[k] = v } fieldsInOrder := [...]string{"id", "name", "password", "roles", "email"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { continue } switch k { case "id": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) data, err := ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } it.ID = data case "name": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Name = data case "password": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("password")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Password = data case "roles": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("roles")) data, err := ec.unmarshalORoleEnum2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnumᚄ(ctx, v) if err != nil { return it, err } it.Roles = data case "email": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("email")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) if err != nil { return it, err } it.Email = data } } return it, nil } // endregion **************************** input.gotpl ***************************** // region ************************** interface.gotpl *************************** func (ec *executionContext) _DraftData(ctx context.Context, sel ast.SelectionSet, obj DraftData) graphql.Marshaler { switch obj := (obj).(type) { case nil: return graphql.Null case SceneDraft: return ec._SceneDraft(ctx, sel, &obj) case *SceneDraft: if obj == nil { return graphql.Null } return ec._SceneDraft(ctx, sel, obj) case PerformerDraft: return ec._PerformerDraft(ctx, sel, &obj) case *PerformerDraft: if obj == nil { return graphql.Null } return ec._PerformerDraft(ctx, sel, obj) default: if typedObj, ok := obj.(graphql.Marshaler); ok { return typedObj } else { panic(fmt.Errorf("unexpected type %T; non-generated variants of DraftData must implement graphql.Marshaler", obj)) } } } func (ec *executionContext) _EditDetails(ctx context.Context, sel ast.SelectionSet, obj EditDetails) graphql.Marshaler { switch obj := (obj).(type) { case nil: return graphql.Null case TagEdit: return ec._TagEdit(ctx, sel, &obj) case *TagEdit: if obj == nil { return graphql.Null } return ec._TagEdit(ctx, sel, obj) case StudioEdit: return ec._StudioEdit(ctx, sel, &obj) case *StudioEdit: if obj == nil { return graphql.Null } return ec._StudioEdit(ctx, sel, obj) case SceneEdit: return ec._SceneEdit(ctx, sel, &obj) case *SceneEdit: if obj == nil { return graphql.Null } return ec._SceneEdit(ctx, sel, obj) case PerformerEdit: return ec._PerformerEdit(ctx, sel, &obj) case *PerformerEdit: if obj == nil { return graphql.Null } return ec._PerformerEdit(ctx, sel, obj) default: if typedObj, ok := obj.(graphql.Marshaler); ok { return typedObj } else { panic(fmt.Errorf("unexpected type %T; non-generated variants of EditDetails must implement graphql.Marshaler", obj)) } } } func (ec *executionContext) _EditTarget(ctx context.Context, sel ast.SelectionSet, obj EditTarget) graphql.Marshaler { switch obj := (obj).(type) { case nil: return graphql.Null case *Tag: if obj == nil { return graphql.Null } return ec._Tag(ctx, sel, obj) case *Studio: if obj == nil { return graphql.Null } return ec._Studio(ctx, sel, obj) case *Scene: if obj == nil { return graphql.Null } return ec._Scene(ctx, sel, obj) case *Performer: if obj == nil { return graphql.Null } return ec._Performer(ctx, sel, obj) default: if typedObj, ok := obj.(graphql.Marshaler); ok { return typedObj } else { panic(fmt.Errorf("unexpected type %T; non-generated variants of EditTarget must implement graphql.Marshaler", obj)) } } } func (ec *executionContext) _NotificationData(ctx context.Context, sel ast.SelectionSet, obj NotificationData) graphql.Marshaler { switch obj := (obj).(type) { case nil: return graphql.Null case UpdatedEdit: return ec._UpdatedEdit(ctx, sel, &obj) case *UpdatedEdit: if obj == nil { return graphql.Null } return ec._UpdatedEdit(ctx, sel, obj) case FingerprintedSceneEdit: return ec._FingerprintedSceneEdit(ctx, sel, &obj) case *FingerprintedSceneEdit: if obj == nil { return graphql.Null } return ec._FingerprintedSceneEdit(ctx, sel, obj) case FavoriteStudioScene: return ec._FavoriteStudioScene(ctx, sel, &obj) case *FavoriteStudioScene: if obj == nil { return graphql.Null } return ec._FavoriteStudioScene(ctx, sel, obj) case FavoriteStudioEdit: return ec._FavoriteStudioEdit(ctx, sel, &obj) case *FavoriteStudioEdit: if obj == nil { return graphql.Null } return ec._FavoriteStudioEdit(ctx, sel, obj) case FavoritePerformerScene: return ec._FavoritePerformerScene(ctx, sel, &obj) case *FavoritePerformerScene: if obj == nil { return graphql.Null } return ec._FavoritePerformerScene(ctx, sel, obj) case FavoritePerformerEdit: return ec._FavoritePerformerEdit(ctx, sel, &obj) case *FavoritePerformerEdit: if obj == nil { return graphql.Null } return ec._FavoritePerformerEdit(ctx, sel, obj) case FailedOwnEdit: return ec._FailedOwnEdit(ctx, sel, &obj) case *FailedOwnEdit: if obj == nil { return graphql.Null } return ec._FailedOwnEdit(ctx, sel, obj) case DownvoteOwnEdit: return ec._DownvoteOwnEdit(ctx, sel, &obj) case *DownvoteOwnEdit: if obj == nil { return graphql.Null } return ec._DownvoteOwnEdit(ctx, sel, obj) case CommentVotedEdit: return ec._CommentVotedEdit(ctx, sel, &obj) case *CommentVotedEdit: if obj == nil { return graphql.Null } return ec._CommentVotedEdit(ctx, sel, obj) case CommentOwnEdit: return ec._CommentOwnEdit(ctx, sel, &obj) case *CommentOwnEdit: if obj == nil { return graphql.Null } return ec._CommentOwnEdit(ctx, sel, obj) case CommentCommentedEdit: return ec._CommentCommentedEdit(ctx, sel, &obj) case *CommentCommentedEdit: if obj == nil { return graphql.Null } return ec._CommentCommentedEdit(ctx, sel, obj) default: if typedObj, ok := obj.(graphql.Marshaler); ok { return typedObj } else { panic(fmt.Errorf("unexpected type %T; non-generated variants of NotificationData must implement graphql.Marshaler", obj)) } } } func (ec *executionContext) _SceneDraftPerformer(ctx context.Context, sel ast.SelectionSet, obj SceneDraftPerformer) graphql.Marshaler { switch obj := (obj).(type) { case nil: return graphql.Null case Performer: return ec._Performer(ctx, sel, &obj) case *Performer: if obj == nil { return graphql.Null } return ec._Performer(ctx, sel, obj) case DraftEntity: return ec._DraftEntity(ctx, sel, &obj) case *DraftEntity: if obj == nil { return graphql.Null } return ec._DraftEntity(ctx, sel, obj) default: if typedObj, ok := obj.(graphql.Marshaler); ok { return typedObj } else { panic(fmt.Errorf("unexpected type %T; non-generated variants of SceneDraftPerformer must implement graphql.Marshaler", obj)) } } } func (ec *executionContext) _SceneDraftStudio(ctx context.Context, sel ast.SelectionSet, obj SceneDraftStudio) graphql.Marshaler { switch obj := (obj).(type) { case nil: return graphql.Null case Studio: return ec._Studio(ctx, sel, &obj) case *Studio: if obj == nil { return graphql.Null } return ec._Studio(ctx, sel, obj) case DraftEntity: return ec._DraftEntity(ctx, sel, &obj) case *DraftEntity: if obj == nil { return graphql.Null } return ec._DraftEntity(ctx, sel, obj) default: if typedObj, ok := obj.(graphql.Marshaler); ok { return typedObj } else { panic(fmt.Errorf("unexpected type %T; non-generated variants of SceneDraftStudio must implement graphql.Marshaler", obj)) } } } func (ec *executionContext) _SceneDraftTag(ctx context.Context, sel ast.SelectionSet, obj SceneDraftTag) graphql.Marshaler { switch obj := (obj).(type) { case nil: return graphql.Null case Tag: return ec._Tag(ctx, sel, &obj) case *Tag: if obj == nil { return graphql.Null } return ec._Tag(ctx, sel, obj) case DraftEntity: return ec._DraftEntity(ctx, sel, &obj) case *DraftEntity: if obj == nil { return graphql.Null } return ec._DraftEntity(ctx, sel, obj) default: if typedObj, ok := obj.(graphql.Marshaler); ok { return typedObj } else { panic(fmt.Errorf("unexpected type %T; non-generated variants of SceneDraftTag must implement graphql.Marshaler", obj)) } } } // endregion ************************** interface.gotpl *************************** // region **************************** object.gotpl **************************** var bodyModificationImplementors = []string{"BodyModification"} func (ec *executionContext) _BodyModification(ctx context.Context, sel ast.SelectionSet, obj *BodyModification) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, bodyModificationImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("BodyModification") case "location": out.Values[i] = ec._BodyModification_location(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "description": out.Values[i] = ec._BodyModification_description(ctx, field, obj) default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var commentCommentedEditImplementors = []string{"CommentCommentedEdit", "NotificationData"} func (ec *executionContext) _CommentCommentedEdit(ctx context.Context, sel ast.SelectionSet, obj *CommentCommentedEdit) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, commentCommentedEditImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("CommentCommentedEdit") case "comment": out.Values[i] = ec._CommentCommentedEdit_comment(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var commentOwnEditImplementors = []string{"CommentOwnEdit", "NotificationData"} func (ec *executionContext) _CommentOwnEdit(ctx context.Context, sel ast.SelectionSet, obj *CommentOwnEdit) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, commentOwnEditImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("CommentOwnEdit") case "comment": out.Values[i] = ec._CommentOwnEdit_comment(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var commentVotedEditImplementors = []string{"CommentVotedEdit", "NotificationData"} func (ec *executionContext) _CommentVotedEdit(ctx context.Context, sel ast.SelectionSet, obj *CommentVotedEdit) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, commentVotedEditImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("CommentVotedEdit") case "comment": out.Values[i] = ec._CommentVotedEdit_comment(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var downvoteOwnEditImplementors = []string{"DownvoteOwnEdit", "NotificationData"} func (ec *executionContext) _DownvoteOwnEdit(ctx context.Context, sel ast.SelectionSet, obj *DownvoteOwnEdit) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, downvoteOwnEditImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("DownvoteOwnEdit") case "edit": out.Values[i] = ec._DownvoteOwnEdit_edit(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var draftImplementors = []string{"Draft"} func (ec *executionContext) _Draft(ctx context.Context, sel ast.SelectionSet, obj *Draft) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, draftImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("Draft") case "id": out.Values[i] = ec._Draft_id(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } case "created": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Draft_created(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "expires": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Draft_expires(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "data": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Draft_data(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var draftEntityImplementors = []string{"DraftEntity", "SceneDraftStudio", "SceneDraftPerformer", "SceneDraftTag"} func (ec *executionContext) _DraftEntity(ctx context.Context, sel ast.SelectionSet, obj *DraftEntity) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, draftEntityImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("DraftEntity") case "name": out.Values[i] = ec._DraftEntity_name(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "id": out.Values[i] = ec._DraftEntity_id(ctx, field, obj) default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var draftFingerprintImplementors = []string{"DraftFingerprint"} func (ec *executionContext) _DraftFingerprint(ctx context.Context, sel ast.SelectionSet, obj *DraftFingerprint) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, draftFingerprintImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("DraftFingerprint") case "hash": out.Values[i] = ec._DraftFingerprint_hash(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "algorithm": out.Values[i] = ec._DraftFingerprint_algorithm(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "duration": out.Values[i] = ec._DraftFingerprint_duration(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var draftSubmissionStatusImplementors = []string{"DraftSubmissionStatus"} func (ec *executionContext) _DraftSubmissionStatus(ctx context.Context, sel ast.SelectionSet, obj *DraftSubmissionStatus) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, draftSubmissionStatusImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("DraftSubmissionStatus") case "id": out.Values[i] = ec._DraftSubmissionStatus_id(ctx, field, obj) default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var editImplementors = []string{"Edit"} func (ec *executionContext) _Edit(ctx context.Context, sel ast.SelectionSet, obj *Edit) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, editImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("Edit") case "id": out.Values[i] = ec._Edit_id(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } case "user": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Edit_user(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "target": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Edit_target(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "target_type": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Edit_target_type(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "merge_sources": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Edit_merge_sources(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "operation": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Edit_operation(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "bot": out.Values[i] = ec._Edit_bot(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } case "details": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Edit_details(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "old_details": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Edit_old_details(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "options": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Edit_options(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "comments": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Edit_comments(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "votes": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Edit_votes(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "vote_count": out.Values[i] = ec._Edit_vote_count(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } case "destructive": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Edit_destructive(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "status": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Edit_status(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "applied": out.Values[i] = ec._Edit_applied(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } case "update_count": out.Values[i] = ec._Edit_update_count(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } case "updatable": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Edit_updatable(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "created": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Edit_created(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "updated": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Edit_updated(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "closed": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Edit_closed(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "expires": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Edit_expires(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var editCommentImplementors = []string{"EditComment"} func (ec *executionContext) _EditComment(ctx context.Context, sel ast.SelectionSet, obj *EditComment) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, editCommentImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("EditComment") case "id": out.Values[i] = ec._EditComment_id(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } case "user": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._EditComment_user(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "date": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._EditComment_date(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "comment": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._EditComment_comment(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "edit": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._EditComment_edit(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var editVoteImplementors = []string{"EditVote"} func (ec *executionContext) _EditVote(ctx context.Context, sel ast.SelectionSet, obj *EditVote) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, editVoteImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("EditVote") case "user": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._EditVote_user(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "date": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._EditVote_date(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "vote": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._EditVote_vote(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var failedOwnEditImplementors = []string{"FailedOwnEdit", "NotificationData"} func (ec *executionContext) _FailedOwnEdit(ctx context.Context, sel ast.SelectionSet, obj *FailedOwnEdit) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, failedOwnEditImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("FailedOwnEdit") case "edit": out.Values[i] = ec._FailedOwnEdit_edit(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var favoritePerformerEditImplementors = []string{"FavoritePerformerEdit", "NotificationData"} func (ec *executionContext) _FavoritePerformerEdit(ctx context.Context, sel ast.SelectionSet, obj *FavoritePerformerEdit) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, favoritePerformerEditImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("FavoritePerformerEdit") case "edit": out.Values[i] = ec._FavoritePerformerEdit_edit(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var favoritePerformerSceneImplementors = []string{"FavoritePerformerScene", "NotificationData"} func (ec *executionContext) _FavoritePerformerScene(ctx context.Context, sel ast.SelectionSet, obj *FavoritePerformerScene) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, favoritePerformerSceneImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("FavoritePerformerScene") case "scene": out.Values[i] = ec._FavoritePerformerScene_scene(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var favoriteStudioEditImplementors = []string{"FavoriteStudioEdit", "NotificationData"} func (ec *executionContext) _FavoriteStudioEdit(ctx context.Context, sel ast.SelectionSet, obj *FavoriteStudioEdit) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, favoriteStudioEditImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("FavoriteStudioEdit") case "edit": out.Values[i] = ec._FavoriteStudioEdit_edit(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var favoriteStudioSceneImplementors = []string{"FavoriteStudioScene", "NotificationData"} func (ec *executionContext) _FavoriteStudioScene(ctx context.Context, sel ast.SelectionSet, obj *FavoriteStudioScene) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, favoriteStudioSceneImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("FavoriteStudioScene") case "scene": out.Values[i] = ec._FavoriteStudioScene_scene(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var fingerprintImplementors = []string{"Fingerprint"} func (ec *executionContext) _Fingerprint(ctx context.Context, sel ast.SelectionSet, obj *Fingerprint) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, fingerprintImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("Fingerprint") case "hash": out.Values[i] = ec._Fingerprint_hash(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "algorithm": out.Values[i] = ec._Fingerprint_algorithm(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "duration": out.Values[i] = ec._Fingerprint_duration(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "submissions": out.Values[i] = ec._Fingerprint_submissions(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "reports": out.Values[i] = ec._Fingerprint_reports(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "created": out.Values[i] = ec._Fingerprint_created(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "updated": out.Values[i] = ec._Fingerprint_updated(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "user_submitted": out.Values[i] = ec._Fingerprint_user_submitted(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "user_reported": out.Values[i] = ec._Fingerprint_user_reported(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var fingerprintSubmissionResultImplementors = []string{"FingerprintSubmissionResult"} func (ec *executionContext) _FingerprintSubmissionResult(ctx context.Context, sel ast.SelectionSet, obj *FingerprintSubmissionResult) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, fingerprintSubmissionResultImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("FingerprintSubmissionResult") case "hash": out.Values[i] = ec._FingerprintSubmissionResult_hash(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "scene_id": out.Values[i] = ec._FingerprintSubmissionResult_scene_id(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "error": out.Values[i] = ec._FingerprintSubmissionResult_error(ctx, field, obj) default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var fingerprintedSceneEditImplementors = []string{"FingerprintedSceneEdit", "NotificationData"} func (ec *executionContext) _FingerprintedSceneEdit(ctx context.Context, sel ast.SelectionSet, obj *FingerprintedSceneEdit) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, fingerprintedSceneEditImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("FingerprintedSceneEdit") case "edit": out.Values[i] = ec._FingerprintedSceneEdit_edit(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var fuzzyDateImplementors = []string{"FuzzyDate"} func (ec *executionContext) _FuzzyDate(ctx context.Context, sel ast.SelectionSet, obj *FuzzyDate) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, fuzzyDateImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("FuzzyDate") case "date": out.Values[i] = ec._FuzzyDate_date(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "accuracy": out.Values[i] = ec._FuzzyDate_accuracy(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var genderFacetImplementors = []string{"GenderFacet"} func (ec *executionContext) _GenderFacet(ctx context.Context, sel ast.SelectionSet, obj *GenderFacet) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, genderFacetImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("GenderFacet") case "gender": out.Values[i] = ec._GenderFacet_gender(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "count": out.Values[i] = ec._GenderFacet_count(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var imageImplementors = []string{"Image"} func (ec *executionContext) _Image(ctx context.Context, sel ast.SelectionSet, obj *Image) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, imageImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("Image") case "id": out.Values[i] = ec._Image_id(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } case "url": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Image_url(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "width": out.Values[i] = ec._Image_width(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } case "height": out.Values[i] = ec._Image_height(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var inviteKeyImplementors = []string{"InviteKey"} func (ec *executionContext) _InviteKey(ctx context.Context, sel ast.SelectionSet, obj *InviteKey) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, inviteKeyImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("InviteKey") case "id": out.Values[i] = ec._InviteKey_id(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "uses": out.Values[i] = ec._InviteKey_uses(ctx, field, obj) case "expires": out.Values[i] = ec._InviteKey_expires(ctx, field, obj) default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var measurementsImplementors = []string{"Measurements"} func (ec *executionContext) _Measurements(ctx context.Context, sel ast.SelectionSet, obj *Measurements) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, measurementsImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("Measurements") case "cup_size": out.Values[i] = ec._Measurements_cup_size(ctx, field, obj) case "band_size": out.Values[i] = ec._Measurements_band_size(ctx, field, obj) case "waist": out.Values[i] = ec._Measurements_waist(ctx, field, obj) case "hip": out.Values[i] = ec._Measurements_hip(ctx, field, obj) default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var modAuditImplementors = []string{"ModAudit"} func (ec *executionContext) _ModAudit(ctx context.Context, sel ast.SelectionSet, obj *ModAudit) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, modAuditImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("ModAudit") case "id": out.Values[i] = ec._ModAudit_id(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } case "action": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._ModAudit_action(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "user": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._ModAudit_user(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "target_id": out.Values[i] = ec._ModAudit_target_id(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } case "target_type": out.Values[i] = ec._ModAudit_target_type(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } case "data": out.Values[i] = ec._ModAudit_data(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } case "reason": out.Values[i] = ec._ModAudit_reason(ctx, field, obj) case "created_at": out.Values[i] = ec._ModAudit_created_at(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var mutationImplementors = []string{"Mutation"} func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, mutationImplementors) ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{ Object: "Mutation", }) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { innerCtx := graphql.WithRootFieldContext(ctx, &graphql.RootFieldContext{ Object: field.Name, Field: field, }) switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("Mutation") case "sceneCreate": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_sceneCreate(ctx, field) }) case "sceneUpdate": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_sceneUpdate(ctx, field) }) case "sceneDestroy": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_sceneDestroy(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "performerCreate": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_performerCreate(ctx, field) }) case "performerUpdate": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_performerUpdate(ctx, field) }) case "performerDestroy": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_performerDestroy(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "studioCreate": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_studioCreate(ctx, field) }) case "studioUpdate": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_studioUpdate(ctx, field) }) case "studioDestroy": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_studioDestroy(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "tagCreate": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_tagCreate(ctx, field) }) case "tagUpdate": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_tagUpdate(ctx, field) }) case "tagDestroy": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_tagDestroy(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "userCreate": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_userCreate(ctx, field) }) case "userUpdate": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_userUpdate(ctx, field) }) case "userDestroy": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_userDestroy(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "imageCreate": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_imageCreate(ctx, field) }) case "imageDestroy": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_imageDestroy(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "newUser": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_newUser(ctx, field) }) case "activateNewUser": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_activateNewUser(ctx, field) }) case "generateInviteCode": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_generateInviteCode(ctx, field) }) case "generateInviteCodes": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_generateInviteCodes(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "rescindInviteCode": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_rescindInviteCode(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "grantInvite": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_grantInvite(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "revokeInvite": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_revokeInvite(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "tagCategoryCreate": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_tagCategoryCreate(ctx, field) }) case "tagCategoryUpdate": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_tagCategoryUpdate(ctx, field) }) case "tagCategoryDestroy": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_tagCategoryDestroy(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "siteCreate": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_siteCreate(ctx, field) }) case "siteUpdate": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_siteUpdate(ctx, field) }) case "siteDestroy": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_siteDestroy(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "regenerateAPIKey": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_regenerateAPIKey(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "resetPassword": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_resetPassword(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "changePassword": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_changePassword(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "requestChangeEmail": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_requestChangeEmail(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "validateChangeEmail": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_validateChangeEmail(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "confirmChangeEmail": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_confirmChangeEmail(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "sceneEdit": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_sceneEdit(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "performerEdit": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_performerEdit(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "studioEdit": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_studioEdit(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "tagEdit": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_tagEdit(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "sceneEditUpdate": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_sceneEditUpdate(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "performerEditUpdate": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_performerEditUpdate(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "studioEditUpdate": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_studioEditUpdate(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "tagEditUpdate": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_tagEditUpdate(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "editVote": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_editVote(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "editComment": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_editComment(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "applyEdit": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_applyEdit(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "cancelEdit": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_cancelEdit(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "deleteEdit": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_deleteEdit(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "amendEdit": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_amendEdit(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "submitFingerprint": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_submitFingerprint(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "submitFingerprints": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_submitFingerprints(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "sceneMoveFingerprintSubmissions": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_sceneMoveFingerprintSubmissions(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "sceneDeleteFingerprintSubmissions": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_sceneDeleteFingerprintSubmissions(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "submitSceneDraft": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_submitSceneDraft(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "submitPerformerDraft": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_submitPerformerDraft(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "destroyDraft": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_destroyDraft(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "favoritePerformer": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_favoritePerformer(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "favoriteStudio": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_favoriteStudio(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "markNotificationsRead": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_markNotificationsRead(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } case "updateNotificationSubscriptions": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_updateNotificationSubscriptions(ctx, field) }) if out.Values[i] == graphql.Null { out.Invalids++ } default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var notificationImplementors = []string{"Notification"} func (ec *executionContext) _Notification(ctx context.Context, sel ast.SelectionSet, obj *Notification) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, notificationImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("Notification") case "created": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Notification_created(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "read": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Notification_read(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "data": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Notification_data(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var performerImplementors = []string{"Performer", "EditTarget", "SceneDraftPerformer"} func (ec *executionContext) _Performer(ctx context.Context, sel ast.SelectionSet, obj *Performer) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, performerImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("Performer") case "id": out.Values[i] = ec._Performer_id(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } case "name": out.Values[i] = ec._Performer_name(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } case "disambiguation": out.Values[i] = ec._Performer_disambiguation(ctx, field, obj) case "aliases": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Performer_aliases(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "gender": out.Values[i] = ec._Performer_gender(ctx, field, obj) case "urls": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Performer_urls(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "birthdate": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Performer_birthdate(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "birth_date": out.Values[i] = ec._Performer_birth_date(ctx, field, obj) case "death_date": out.Values[i] = ec._Performer_death_date(ctx, field, obj) case "age": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Performer_age(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "ethnicity": out.Values[i] = ec._Performer_ethnicity(ctx, field, obj) case "country": out.Values[i] = ec._Performer_country(ctx, field, obj) case "eye_color": out.Values[i] = ec._Performer_eye_color(ctx, field, obj) case "hair_color": out.Values[i] = ec._Performer_hair_color(ctx, field, obj) case "height": out.Values[i] = ec._Performer_height(ctx, field, obj) case "measurements": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Performer_measurements(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "cup_size": out.Values[i] = ec._Performer_cup_size(ctx, field, obj) case "band_size": out.Values[i] = ec._Performer_band_size(ctx, field, obj) case "waist_size": out.Values[i] = ec._Performer_waist_size(ctx, field, obj) case "hip_size": out.Values[i] = ec._Performer_hip_size(ctx, field, obj) case "breast_type": out.Values[i] = ec._Performer_breast_type(ctx, field, obj) case "career_start_year": out.Values[i] = ec._Performer_career_start_year(ctx, field, obj) case "career_end_year": out.Values[i] = ec._Performer_career_end_year(ctx, field, obj) case "tattoos": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Performer_tattoos(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "piercings": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Performer_piercings(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "images": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Performer_images(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "deleted": out.Values[i] = ec._Performer_deleted(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } case "edits": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Performer_edits(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "scene_count": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Performer_scene_count(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "scenes": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Performer_scenes(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "merged_ids": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Performer_merged_ids(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "merged_into_id": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Performer_merged_into_id(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "studios": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Performer_studios(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "is_favorite": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Performer_is_favorite(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "created": out.Values[i] = ec._Performer_created(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } case "updated": out.Values[i] = ec._Performer_updated(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var performerAppearanceImplementors = []string{"PerformerAppearance"} func (ec *executionContext) _PerformerAppearance(ctx context.Context, sel ast.SelectionSet, obj *PerformerAppearance) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, performerAppearanceImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("PerformerAppearance") case "performer": out.Values[i] = ec._PerformerAppearance_performer(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "as": out.Values[i] = ec._PerformerAppearance_as(ctx, field, obj) default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var performerDraftImplementors = []string{"PerformerDraft", "DraftData"} func (ec *executionContext) _PerformerDraft(ctx context.Context, sel ast.SelectionSet, obj *PerformerDraft) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, performerDraftImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("PerformerDraft") case "id": out.Values[i] = ec._PerformerDraft_id(ctx, field, obj) case "name": out.Values[i] = ec._PerformerDraft_name(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } case "disambiguation": out.Values[i] = ec._PerformerDraft_disambiguation(ctx, field, obj) case "aliases": out.Values[i] = ec._PerformerDraft_aliases(ctx, field, obj) case "gender": out.Values[i] = ec._PerformerDraft_gender(ctx, field, obj) case "birthdate": out.Values[i] = ec._PerformerDraft_birthdate(ctx, field, obj) case "deathdate": out.Values[i] = ec._PerformerDraft_deathdate(ctx, field, obj) case "urls": out.Values[i] = ec._PerformerDraft_urls(ctx, field, obj) case "ethnicity": out.Values[i] = ec._PerformerDraft_ethnicity(ctx, field, obj) case "country": out.Values[i] = ec._PerformerDraft_country(ctx, field, obj) case "eye_color": out.Values[i] = ec._PerformerDraft_eye_color(ctx, field, obj) case "hair_color": out.Values[i] = ec._PerformerDraft_hair_color(ctx, field, obj) case "height": out.Values[i] = ec._PerformerDraft_height(ctx, field, obj) case "measurements": out.Values[i] = ec._PerformerDraft_measurements(ctx, field, obj) case "breast_type": out.Values[i] = ec._PerformerDraft_breast_type(ctx, field, obj) case "tattoos": out.Values[i] = ec._PerformerDraft_tattoos(ctx, field, obj) case "piercings": out.Values[i] = ec._PerformerDraft_piercings(ctx, field, obj) case "career_start_year": out.Values[i] = ec._PerformerDraft_career_start_year(ctx, field, obj) case "career_end_year": out.Values[i] = ec._PerformerDraft_career_end_year(ctx, field, obj) case "image": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._PerformerDraft_image(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var performerEditImplementors = []string{"PerformerEdit", "EditDetails"} func (ec *executionContext) _PerformerEdit(ctx context.Context, sel ast.SelectionSet, obj *PerformerEdit) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, performerEditImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("PerformerEdit") case "name": out.Values[i] = ec._PerformerEdit_name(ctx, field, obj) case "disambiguation": out.Values[i] = ec._PerformerEdit_disambiguation(ctx, field, obj) case "added_aliases": out.Values[i] = ec._PerformerEdit_added_aliases(ctx, field, obj) case "removed_aliases": out.Values[i] = ec._PerformerEdit_removed_aliases(ctx, field, obj) case "gender": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._PerformerEdit_gender(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "added_urls": out.Values[i] = ec._PerformerEdit_added_urls(ctx, field, obj) case "removed_urls": out.Values[i] = ec._PerformerEdit_removed_urls(ctx, field, obj) case "birthdate": out.Values[i] = ec._PerformerEdit_birthdate(ctx, field, obj) case "deathdate": out.Values[i] = ec._PerformerEdit_deathdate(ctx, field, obj) case "ethnicity": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._PerformerEdit_ethnicity(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "country": out.Values[i] = ec._PerformerEdit_country(ctx, field, obj) case "eye_color": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._PerformerEdit_eye_color(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "hair_color": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._PerformerEdit_hair_color(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "height": out.Values[i] = ec._PerformerEdit_height(ctx, field, obj) case "cup_size": out.Values[i] = ec._PerformerEdit_cup_size(ctx, field, obj) case "band_size": out.Values[i] = ec._PerformerEdit_band_size(ctx, field, obj) case "waist_size": out.Values[i] = ec._PerformerEdit_waist_size(ctx, field, obj) case "hip_size": out.Values[i] = ec._PerformerEdit_hip_size(ctx, field, obj) case "breast_type": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._PerformerEdit_breast_type(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "career_start_year": out.Values[i] = ec._PerformerEdit_career_start_year(ctx, field, obj) case "career_end_year": out.Values[i] = ec._PerformerEdit_career_end_year(ctx, field, obj) case "added_tattoos": out.Values[i] = ec._PerformerEdit_added_tattoos(ctx, field, obj) case "removed_tattoos": out.Values[i] = ec._PerformerEdit_removed_tattoos(ctx, field, obj) case "added_piercings": out.Values[i] = ec._PerformerEdit_added_piercings(ctx, field, obj) case "removed_piercings": out.Values[i] = ec._PerformerEdit_removed_piercings(ctx, field, obj) case "added_images": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._PerformerEdit_added_images(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "removed_images": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._PerformerEdit_removed_images(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "draft_id": out.Values[i] = ec._PerformerEdit_draft_id(ctx, field, obj) case "aliases": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._PerformerEdit_aliases(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "urls": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._PerformerEdit_urls(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "images": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._PerformerEdit_images(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "tattoos": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._PerformerEdit_tattoos(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "piercings": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._PerformerEdit_piercings(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var performerEditOptionsImplementors = []string{"PerformerEditOptions"} func (ec *executionContext) _PerformerEditOptions(ctx context.Context, sel ast.SelectionSet, obj *PerformerEditOptions) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, performerEditOptionsImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("PerformerEditOptions") case "set_modify_aliases": out.Values[i] = ec._PerformerEditOptions_set_modify_aliases(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "set_merge_aliases": out.Values[i] = ec._PerformerEditOptions_set_merge_aliases(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var performerSearchFacetsImplementors = []string{"PerformerSearchFacets"} func (ec *executionContext) _PerformerSearchFacets(ctx context.Context, sel ast.SelectionSet, obj *PerformerSearchFacets) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, performerSearchFacetsImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("PerformerSearchFacets") case "genders": out.Values[i] = ec._PerformerSearchFacets_genders(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var performerStudioImplementors = []string{"PerformerStudio"} func (ec *executionContext) _PerformerStudio(ctx context.Context, sel ast.SelectionSet, obj *PerformerStudio) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, performerStudioImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("PerformerStudio") case "studio": out.Values[i] = ec._PerformerStudio_studio(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "scene_count": out.Values[i] = ec._PerformerStudio_scene_count(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var queryImplementors = []string{"Query"} func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, queryImplementors) ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{ Object: "Query", }) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { innerCtx := graphql.WithRootFieldContext(ctx, &graphql.RootFieldContext{ Object: field.Name, Field: field, }) switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("Query") case "findPerformer": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Query_findPerformer(ctx, field) return res } rrm := func(ctx context.Context) graphql.Marshaler { return ec.OperationContext.RootResolverMiddleware(ctx, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "queryPerformers": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Query_queryPerformers(ctx, field) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } rrm := func(ctx context.Context) graphql.Marshaler { return ec.OperationContext.RootResolverMiddleware(ctx, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "findStudio": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Query_findStudio(ctx, field) return res } rrm := func(ctx context.Context) graphql.Marshaler { return ec.OperationContext.RootResolverMiddleware(ctx, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "queryStudios": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Query_queryStudios(ctx, field) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } rrm := func(ctx context.Context) graphql.Marshaler { return ec.OperationContext.RootResolverMiddleware(ctx, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "findTag": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Query_findTag(ctx, field) return res } rrm := func(ctx context.Context) graphql.Marshaler { return ec.OperationContext.RootResolverMiddleware(ctx, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "findTagOrAlias": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Query_findTagOrAlias(ctx, field) return res } rrm := func(ctx context.Context) graphql.Marshaler { return ec.OperationContext.RootResolverMiddleware(ctx, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "queryTags": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Query_queryTags(ctx, field) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } rrm := func(ctx context.Context) graphql.Marshaler { return ec.OperationContext.RootResolverMiddleware(ctx, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "findTagCategory": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Query_findTagCategory(ctx, field) return res } rrm := func(ctx context.Context) graphql.Marshaler { return ec.OperationContext.RootResolverMiddleware(ctx, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "queryTagCategories": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Query_queryTagCategories(ctx, field) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } rrm := func(ctx context.Context) graphql.Marshaler { return ec.OperationContext.RootResolverMiddleware(ctx, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "findScene": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Query_findScene(ctx, field) return res } rrm := func(ctx context.Context) graphql.Marshaler { return ec.OperationContext.RootResolverMiddleware(ctx, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "findScenesBySceneFingerprints": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Query_findScenesBySceneFingerprints(ctx, field) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } rrm := func(ctx context.Context) graphql.Marshaler { return ec.OperationContext.RootResolverMiddleware(ctx, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "queryScenes": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Query_queryScenes(ctx, field) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } rrm := func(ctx context.Context) graphql.Marshaler { return ec.OperationContext.RootResolverMiddleware(ctx, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "findSite": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Query_findSite(ctx, field) return res } rrm := func(ctx context.Context) graphql.Marshaler { return ec.OperationContext.RootResolverMiddleware(ctx, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "querySites": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Query_querySites(ctx, field) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } rrm := func(ctx context.Context) graphql.Marshaler { return ec.OperationContext.RootResolverMiddleware(ctx, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "findEdit": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Query_findEdit(ctx, field) return res } rrm := func(ctx context.Context) graphql.Marshaler { return ec.OperationContext.RootResolverMiddleware(ctx, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "queryEdits": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Query_queryEdits(ctx, field) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } rrm := func(ctx context.Context) graphql.Marshaler { return ec.OperationContext.RootResolverMiddleware(ctx, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "findUser": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Query_findUser(ctx, field) return res } rrm := func(ctx context.Context) graphql.Marshaler { return ec.OperationContext.RootResolverMiddleware(ctx, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "queryUsers": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Query_queryUsers(ctx, field) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } rrm := func(ctx context.Context) graphql.Marshaler { return ec.OperationContext.RootResolverMiddleware(ctx, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "me": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Query_me(ctx, field) return res } rrm := func(ctx context.Context) graphql.Marshaler { return ec.OperationContext.RootResolverMiddleware(ctx, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "searchPerformer": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Query_searchPerformer(ctx, field) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } rrm := func(ctx context.Context) graphql.Marshaler { return ec.OperationContext.RootResolverMiddleware(ctx, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "searchPerformers": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Query_searchPerformers(ctx, field) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } rrm := func(ctx context.Context) graphql.Marshaler { return ec.OperationContext.RootResolverMiddleware(ctx, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "searchScene": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Query_searchScene(ctx, field) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } rrm := func(ctx context.Context) graphql.Marshaler { return ec.OperationContext.RootResolverMiddleware(ctx, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "searchScenes": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Query_searchScenes(ctx, field) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } rrm := func(ctx context.Context) graphql.Marshaler { return ec.OperationContext.RootResolverMiddleware(ctx, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "searchTag": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Query_searchTag(ctx, field) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } rrm := func(ctx context.Context) graphql.Marshaler { return ec.OperationContext.RootResolverMiddleware(ctx, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "searchStudio": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Query_searchStudio(ctx, field) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } rrm := func(ctx context.Context) graphql.Marshaler { return ec.OperationContext.RootResolverMiddleware(ctx, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "findDraft": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Query_findDraft(ctx, field) return res } rrm := func(ctx context.Context) graphql.Marshaler { return ec.OperationContext.RootResolverMiddleware(ctx, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "findDrafts": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Query_findDrafts(ctx, field) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } rrm := func(ctx context.Context) graphql.Marshaler { return ec.OperationContext.RootResolverMiddleware(ctx, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "queryExistingScene": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Query_queryExistingScene(ctx, field) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } rrm := func(ctx context.Context) graphql.Marshaler { return ec.OperationContext.RootResolverMiddleware(ctx, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "queryExistingPerformer": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Query_queryExistingPerformer(ctx, field) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } rrm := func(ctx context.Context) graphql.Marshaler { return ec.OperationContext.RootResolverMiddleware(ctx, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "version": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Query_version(ctx, field) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } rrm := func(ctx context.Context) graphql.Marshaler { return ec.OperationContext.RootResolverMiddleware(ctx, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "getConfig": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Query_getConfig(ctx, field) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } rrm := func(ctx context.Context) graphql.Marshaler { return ec.OperationContext.RootResolverMiddleware(ctx, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "queryNotifications": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Query_queryNotifications(ctx, field) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } rrm := func(ctx context.Context) graphql.Marshaler { return ec.OperationContext.RootResolverMiddleware(ctx, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "getUnreadNotificationCount": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Query_getUnreadNotificationCount(ctx, field) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } rrm := func(ctx context.Context) graphql.Marshaler { return ec.OperationContext.RootResolverMiddleware(ctx, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "queryModAudits": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Query_queryModAudits(ctx, field) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } rrm := func(ctx context.Context) graphql.Marshaler { return ec.OperationContext.RootResolverMiddleware(ctx, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "__type": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Query___type(ctx, field) }) case "__schema": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Query___schema(ctx, field) }) default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var queryEditsResultTypeImplementors = []string{"QueryEditsResultType"} func (ec *executionContext) _QueryEditsResultType(ctx context.Context, sel ast.SelectionSet, obj *EditQuery) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, queryEditsResultTypeImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("QueryEditsResultType") case "count": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._QueryEditsResultType_count(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "edits": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._QueryEditsResultType_edits(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var queryExistingPerformerResultImplementors = []string{"QueryExistingPerformerResult"} func (ec *executionContext) _QueryExistingPerformerResult(ctx context.Context, sel ast.SelectionSet, obj *QueryExistingPerformerResult) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, queryExistingPerformerResultImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("QueryExistingPerformerResult") case "edits": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._QueryExistingPerformerResult_edits(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "performers": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._QueryExistingPerformerResult_performers(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var queryExistingSceneResultImplementors = []string{"QueryExistingSceneResult"} func (ec *executionContext) _QueryExistingSceneResult(ctx context.Context, sel ast.SelectionSet, obj *QueryExistingSceneResult) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, queryExistingSceneResultImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("QueryExistingSceneResult") case "edits": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._QueryExistingSceneResult_edits(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "scenes": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._QueryExistingSceneResult_scenes(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var queryModAuditsResultTypeImplementors = []string{"QueryModAuditsResultType"} func (ec *executionContext) _QueryModAuditsResultType(ctx context.Context, sel ast.SelectionSet, obj *ModAuditQuery) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, queryModAuditsResultTypeImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("QueryModAuditsResultType") case "count": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._QueryModAuditsResultType_count(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "audits": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._QueryModAuditsResultType_audits(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var queryNotificationsResultImplementors = []string{"QueryNotificationsResult"} func (ec *executionContext) _QueryNotificationsResult(ctx context.Context, sel ast.SelectionSet, obj *QueryNotificationsResult) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, queryNotificationsResultImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("QueryNotificationsResult") case "count": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._QueryNotificationsResult_count(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "notifications": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._QueryNotificationsResult_notifications(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var queryPerformersResultTypeImplementors = []string{"QueryPerformersResultType"} func (ec *executionContext) _QueryPerformersResultType(ctx context.Context, sel ast.SelectionSet, obj *PerformerQuery) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, queryPerformersResultTypeImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("QueryPerformersResultType") case "count": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._QueryPerformersResultType_count(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "performers": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._QueryPerformersResultType_performers(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "facets": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._QueryPerformersResultType_facets(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var queryScenesResultTypeImplementors = []string{"QueryScenesResultType"} func (ec *executionContext) _QueryScenesResultType(ctx context.Context, sel ast.SelectionSet, obj *SceneQuery) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, queryScenesResultTypeImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("QueryScenesResultType") case "count": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._QueryScenesResultType_count(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "scenes": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._QueryScenesResultType_scenes(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var querySitesResultTypeImplementors = []string{"QuerySitesResultType"} func (ec *executionContext) _QuerySitesResultType(ctx context.Context, sel ast.SelectionSet, obj *QuerySitesResultType) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, querySitesResultTypeImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("QuerySitesResultType") case "count": out.Values[i] = ec._QuerySitesResultType_count(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "sites": out.Values[i] = ec._QuerySitesResultType_sites(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var queryStudiosResultTypeImplementors = []string{"QueryStudiosResultType"} func (ec *executionContext) _QueryStudiosResultType(ctx context.Context, sel ast.SelectionSet, obj *QueryStudiosResultType) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, queryStudiosResultTypeImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("QueryStudiosResultType") case "count": out.Values[i] = ec._QueryStudiosResultType_count(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "studios": out.Values[i] = ec._QueryStudiosResultType_studios(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var queryTagCategoriesResultTypeImplementors = []string{"QueryTagCategoriesResultType"} func (ec *executionContext) _QueryTagCategoriesResultType(ctx context.Context, sel ast.SelectionSet, obj *QueryTagCategoriesResultType) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, queryTagCategoriesResultTypeImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("QueryTagCategoriesResultType") case "count": out.Values[i] = ec._QueryTagCategoriesResultType_count(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "tag_categories": out.Values[i] = ec._QueryTagCategoriesResultType_tag_categories(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var queryTagsResultTypeImplementors = []string{"QueryTagsResultType"} func (ec *executionContext) _QueryTagsResultType(ctx context.Context, sel ast.SelectionSet, obj *QueryTagsResultType) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, queryTagsResultTypeImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("QueryTagsResultType") case "count": out.Values[i] = ec._QueryTagsResultType_count(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "tags": out.Values[i] = ec._QueryTagsResultType_tags(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var queryUsersResultTypeImplementors = []string{"QueryUsersResultType"} func (ec *executionContext) _QueryUsersResultType(ctx context.Context, sel ast.SelectionSet, obj *QueryUsersResultType) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, queryUsersResultTypeImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("QueryUsersResultType") case "count": out.Values[i] = ec._QueryUsersResultType_count(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "users": out.Values[i] = ec._QueryUsersResultType_users(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var sceneImplementors = []string{"Scene", "EditTarget"} func (ec *executionContext) _Scene(ctx context.Context, sel ast.SelectionSet, obj *Scene) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, sceneImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("Scene") case "id": out.Values[i] = ec._Scene_id(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } case "title": out.Values[i] = ec._Scene_title(ctx, field, obj) case "details": out.Values[i] = ec._Scene_details(ctx, field, obj) case "date": out.Values[i] = ec._Scene_date(ctx, field, obj) case "release_date": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Scene_release_date(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "production_date": out.Values[i] = ec._Scene_production_date(ctx, field, obj) case "urls": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Scene_urls(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "studio": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Scene_studio(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "tags": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Scene_tags(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "images": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Scene_images(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "performers": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Scene_performers(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "fingerprints": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Scene_fingerprints(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "duration": out.Values[i] = ec._Scene_duration(ctx, field, obj) case "director": out.Values[i] = ec._Scene_director(ctx, field, obj) case "code": out.Values[i] = ec._Scene_code(ctx, field, obj) case "deleted": out.Values[i] = ec._Scene_deleted(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } case "edits": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Scene_edits(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "created": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Scene_created(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "updated": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Scene_updated(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var sceneDraftImplementors = []string{"SceneDraft", "DraftData"} func (ec *executionContext) _SceneDraft(ctx context.Context, sel ast.SelectionSet, obj *SceneDraft) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, sceneDraftImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("SceneDraft") case "id": out.Values[i] = ec._SceneDraft_id(ctx, field, obj) case "title": out.Values[i] = ec._SceneDraft_title(ctx, field, obj) case "code": out.Values[i] = ec._SceneDraft_code(ctx, field, obj) case "details": out.Values[i] = ec._SceneDraft_details(ctx, field, obj) case "director": out.Values[i] = ec._SceneDraft_director(ctx, field, obj) case "urls": out.Values[i] = ec._SceneDraft_urls(ctx, field, obj) case "date": out.Values[i] = ec._SceneDraft_date(ctx, field, obj) case "production_date": out.Values[i] = ec._SceneDraft_production_date(ctx, field, obj) case "studio": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._SceneDraft_studio(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "performers": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._SceneDraft_performers(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "tags": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._SceneDraft_tags(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "image": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._SceneDraft_image(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "fingerprints": out.Values[i] = ec._SceneDraft_fingerprints(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var sceneEditImplementors = []string{"SceneEdit", "EditDetails"} func (ec *executionContext) _SceneEdit(ctx context.Context, sel ast.SelectionSet, obj *SceneEdit) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, sceneEditImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("SceneEdit") case "title": out.Values[i] = ec._SceneEdit_title(ctx, field, obj) case "details": out.Values[i] = ec._SceneEdit_details(ctx, field, obj) case "added_urls": out.Values[i] = ec._SceneEdit_added_urls(ctx, field, obj) case "removed_urls": out.Values[i] = ec._SceneEdit_removed_urls(ctx, field, obj) case "date": out.Values[i] = ec._SceneEdit_date(ctx, field, obj) case "production_date": out.Values[i] = ec._SceneEdit_production_date(ctx, field, obj) case "studio": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._SceneEdit_studio(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "added_performers": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._SceneEdit_added_performers(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "removed_performers": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._SceneEdit_removed_performers(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "added_tags": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._SceneEdit_added_tags(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "removed_tags": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._SceneEdit_removed_tags(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "added_images": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._SceneEdit_added_images(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "removed_images": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._SceneEdit_removed_images(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "added_fingerprints": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._SceneEdit_added_fingerprints(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "removed_fingerprints": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._SceneEdit_removed_fingerprints(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "duration": out.Values[i] = ec._SceneEdit_duration(ctx, field, obj) case "director": out.Values[i] = ec._SceneEdit_director(ctx, field, obj) case "code": out.Values[i] = ec._SceneEdit_code(ctx, field, obj) case "draft_id": out.Values[i] = ec._SceneEdit_draft_id(ctx, field, obj) case "urls": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._SceneEdit_urls(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "performers": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._SceneEdit_performers(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "tags": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._SceneEdit_tags(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "images": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._SceneEdit_images(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "fingerprints": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._SceneEdit_fingerprints(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var siteImplementors = []string{"Site"} func (ec *executionContext) _Site(ctx context.Context, sel ast.SelectionSet, obj *Site) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, siteImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("Site") case "id": out.Values[i] = ec._Site_id(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } case "name": out.Values[i] = ec._Site_name(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } case "description": out.Values[i] = ec._Site_description(ctx, field, obj) case "url": out.Values[i] = ec._Site_url(ctx, field, obj) case "regex": out.Values[i] = ec._Site_regex(ctx, field, obj) case "valid_types": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Site_valid_types(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "icon": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Site_icon(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "created": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Site_created(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "updated": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Site_updated(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var stashBoxConfigImplementors = []string{"StashBoxConfig"} func (ec *executionContext) _StashBoxConfig(ctx context.Context, sel ast.SelectionSet, obj *StashBoxConfig) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, stashBoxConfigImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("StashBoxConfig") case "host_url": out.Values[i] = ec._StashBoxConfig_host_url(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "require_invite": out.Values[i] = ec._StashBoxConfig_require_invite(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "require_activation": out.Values[i] = ec._StashBoxConfig_require_activation(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "vote_promotion_threshold": out.Values[i] = ec._StashBoxConfig_vote_promotion_threshold(ctx, field, obj) case "vote_application_threshold": out.Values[i] = ec._StashBoxConfig_vote_application_threshold(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "voting_period": out.Values[i] = ec._StashBoxConfig_voting_period(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "min_destructive_voting_period": out.Values[i] = ec._StashBoxConfig_min_destructive_voting_period(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "vote_cron_interval": out.Values[i] = ec._StashBoxConfig_vote_cron_interval(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "guidelines_url": out.Values[i] = ec._StashBoxConfig_guidelines_url(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "require_scene_draft": out.Values[i] = ec._StashBoxConfig_require_scene_draft(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "edit_update_limit": out.Values[i] = ec._StashBoxConfig_edit_update_limit(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "require_tag_role": out.Values[i] = ec._StashBoxConfig_require_tag_role(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var studioImplementors = []string{"Studio", "EditTarget", "SceneDraftStudio"} func (ec *executionContext) _Studio(ctx context.Context, sel ast.SelectionSet, obj *Studio) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, studioImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("Studio") case "id": out.Values[i] = ec._Studio_id(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } case "name": out.Values[i] = ec._Studio_name(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } case "aliases": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Studio_aliases(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "urls": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Studio_urls(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "parent": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Studio_parent(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "child_studios": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Studio_child_studios(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "sub_studios": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Studio_sub_studios(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "images": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Studio_images(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "deleted": out.Values[i] = ec._Studio_deleted(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } case "is_favorite": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Studio_is_favorite(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "created": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Studio_created(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "updated": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Studio_updated(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "performers": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Studio_performers(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var studioEditImplementors = []string{"StudioEdit", "EditDetails"} func (ec *executionContext) _StudioEdit(ctx context.Context, sel ast.SelectionSet, obj *StudioEdit) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, studioEditImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("StudioEdit") case "name": out.Values[i] = ec._StudioEdit_name(ctx, field, obj) case "added_urls": out.Values[i] = ec._StudioEdit_added_urls(ctx, field, obj) case "removed_urls": out.Values[i] = ec._StudioEdit_removed_urls(ctx, field, obj) case "parent": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._StudioEdit_parent(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "added_images": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._StudioEdit_added_images(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "removed_images": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._StudioEdit_removed_images(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "added_aliases": out.Values[i] = ec._StudioEdit_added_aliases(ctx, field, obj) case "removed_aliases": out.Values[i] = ec._StudioEdit_removed_aliases(ctx, field, obj) case "images": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._StudioEdit_images(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "urls": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._StudioEdit_urls(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var tagImplementors = []string{"Tag", "EditTarget", "SceneDraftTag"} func (ec *executionContext) _Tag(ctx context.Context, sel ast.SelectionSet, obj *Tag) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, tagImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("Tag") case "id": out.Values[i] = ec._Tag_id(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } case "name": out.Values[i] = ec._Tag_name(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } case "description": out.Values[i] = ec._Tag_description(ctx, field, obj) case "aliases": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Tag_aliases(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "deleted": out.Values[i] = ec._Tag_deleted(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } case "edits": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Tag_edits(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "category": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._Tag_category(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "created": out.Values[i] = ec._Tag_created(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } case "updated": out.Values[i] = ec._Tag_updated(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var tagCategoryImplementors = []string{"TagCategory"} func (ec *executionContext) _TagCategory(ctx context.Context, sel ast.SelectionSet, obj *TagCategory) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, tagCategoryImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("TagCategory") case "id": out.Values[i] = ec._TagCategory_id(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } case "name": out.Values[i] = ec._TagCategory_name(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } case "group": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._TagCategory_group(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "description": out.Values[i] = ec._TagCategory_description(ctx, field, obj) default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var tagEditImplementors = []string{"TagEdit", "EditDetails"} func (ec *executionContext) _TagEdit(ctx context.Context, sel ast.SelectionSet, obj *TagEdit) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, tagEditImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("TagEdit") case "name": out.Values[i] = ec._TagEdit_name(ctx, field, obj) case "description": out.Values[i] = ec._TagEdit_description(ctx, field, obj) case "added_aliases": out.Values[i] = ec._TagEdit_added_aliases(ctx, field, obj) case "removed_aliases": out.Values[i] = ec._TagEdit_removed_aliases(ctx, field, obj) case "category": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._TagEdit_category(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "aliases": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._TagEdit_aliases(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var uRLImplementors = []string{"URL"} func (ec *executionContext) _URL(ctx context.Context, sel ast.SelectionSet, obj *URL) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, uRLImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("URL") case "url": out.Values[i] = ec._URL_url(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } case "type": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._URL_type(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "site": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._URL_site(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var updatedEditImplementors = []string{"UpdatedEdit", "NotificationData"} func (ec *executionContext) _UpdatedEdit(ctx context.Context, sel ast.SelectionSet, obj *UpdatedEdit) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, updatedEditImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("UpdatedEdit") case "edit": out.Values[i] = ec._UpdatedEdit_edit(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var userImplementors = []string{"User"} func (ec *executionContext) _User(ctx context.Context, sel ast.SelectionSet, obj *User) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, userImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("User") case "id": out.Values[i] = ec._User_id(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } case "name": out.Values[i] = ec._User_name(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } case "roles": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._User_roles(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "email": out.Values[i] = ec._User_email(ctx, field, obj) case "api_key": out.Values[i] = ec._User_api_key(ctx, field, obj) case "notification_subscriptions": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._User_notification_subscriptions(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "vote_count": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._User_vote_count(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "edit_count": field := field innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._User_edit_count(ctx, field, obj) if res == graphql.Null { atomic.AddUint32(&fs.Invalids, 1) } return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "api_calls": out.Values[i] = ec._User_api_calls(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } case "invited_by": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._User_invited_by(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "invite_tokens": out.Values[i] = ec._User_invite_tokens(ctx, field, obj) case "active_invite_codes": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._User_active_invite_codes(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "invite_codes": field := field innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) } }() res = ec._User_invite_codes(ctx, field, obj) return res } if field.Deferrable != nil { dfs, ok := deferred[field.Deferrable.Label] di := 0 if ok { dfs.AddField(field) di = len(dfs.Values) - 1 } else { dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) deferred[field.Deferrable.Label] = dfs } dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, dfs) }) // don't run the out.Concurrently() call below out.Values[i] = graphql.Null continue } out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var userEditCountImplementors = []string{"UserEditCount"} func (ec *executionContext) _UserEditCount(ctx context.Context, sel ast.SelectionSet, obj *UserEditCount) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, userEditCountImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("UserEditCount") case "accepted": out.Values[i] = ec._UserEditCount_accepted(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "rejected": out.Values[i] = ec._UserEditCount_rejected(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "pending": out.Values[i] = ec._UserEditCount_pending(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "immediate_accepted": out.Values[i] = ec._UserEditCount_immediate_accepted(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "immediate_rejected": out.Values[i] = ec._UserEditCount_immediate_rejected(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "failed": out.Values[i] = ec._UserEditCount_failed(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "canceled": out.Values[i] = ec._UserEditCount_canceled(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var userVoteCountImplementors = []string{"UserVoteCount"} func (ec *executionContext) _UserVoteCount(ctx context.Context, sel ast.SelectionSet, obj *UserVoteCount) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, userVoteCountImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("UserVoteCount") case "abstain": out.Values[i] = ec._UserVoteCount_abstain(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "accept": out.Values[i] = ec._UserVoteCount_accept(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "reject": out.Values[i] = ec._UserVoteCount_reject(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "immediate_accept": out.Values[i] = ec._UserVoteCount_immediate_accept(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "immediate_reject": out.Values[i] = ec._UserVoteCount_immediate_reject(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var versionImplementors = []string{"Version"} func (ec *executionContext) _Version(ctx context.Context, sel ast.SelectionSet, obj *Version) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, versionImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("Version") case "hash": out.Values[i] = ec._Version_hash(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "build_time": out.Values[i] = ec._Version_build_time(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "build_type": out.Values[i] = ec._Version_build_type(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "version": out.Values[i] = ec._Version_version(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var __DirectiveImplementors = []string{"__Directive"} func (ec *executionContext) ___Directive(ctx context.Context, sel ast.SelectionSet, obj *introspection.Directive) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, __DirectiveImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("__Directive") case "name": out.Values[i] = ec.___Directive_name(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "description": out.Values[i] = ec.___Directive_description(ctx, field, obj) case "isRepeatable": out.Values[i] = ec.___Directive_isRepeatable(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "locations": out.Values[i] = ec.___Directive_locations(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "args": out.Values[i] = ec.___Directive_args(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var __EnumValueImplementors = []string{"__EnumValue"} func (ec *executionContext) ___EnumValue(ctx context.Context, sel ast.SelectionSet, obj *introspection.EnumValue) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, __EnumValueImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("__EnumValue") case "name": out.Values[i] = ec.___EnumValue_name(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "description": out.Values[i] = ec.___EnumValue_description(ctx, field, obj) case "isDeprecated": out.Values[i] = ec.___EnumValue_isDeprecated(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "deprecationReason": out.Values[i] = ec.___EnumValue_deprecationReason(ctx, field, obj) default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var __FieldImplementors = []string{"__Field"} func (ec *executionContext) ___Field(ctx context.Context, sel ast.SelectionSet, obj *introspection.Field) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, __FieldImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("__Field") case "name": out.Values[i] = ec.___Field_name(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "description": out.Values[i] = ec.___Field_description(ctx, field, obj) case "args": out.Values[i] = ec.___Field_args(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "type": out.Values[i] = ec.___Field_type(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "isDeprecated": out.Values[i] = ec.___Field_isDeprecated(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "deprecationReason": out.Values[i] = ec.___Field_deprecationReason(ctx, field, obj) default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var __InputValueImplementors = []string{"__InputValue"} func (ec *executionContext) ___InputValue(ctx context.Context, sel ast.SelectionSet, obj *introspection.InputValue) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, __InputValueImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("__InputValue") case "name": out.Values[i] = ec.___InputValue_name(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "description": out.Values[i] = ec.___InputValue_description(ctx, field, obj) case "type": out.Values[i] = ec.___InputValue_type(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "defaultValue": out.Values[i] = ec.___InputValue_defaultValue(ctx, field, obj) case "isDeprecated": out.Values[i] = ec.___InputValue_isDeprecated(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "deprecationReason": out.Values[i] = ec.___InputValue_deprecationReason(ctx, field, obj) default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var __SchemaImplementors = []string{"__Schema"} func (ec *executionContext) ___Schema(ctx context.Context, sel ast.SelectionSet, obj *introspection.Schema) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, __SchemaImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("__Schema") case "description": out.Values[i] = ec.___Schema_description(ctx, field, obj) case "types": out.Values[i] = ec.___Schema_types(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "queryType": out.Values[i] = ec.___Schema_queryType(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "mutationType": out.Values[i] = ec.___Schema_mutationType(ctx, field, obj) case "subscriptionType": out.Values[i] = ec.___Schema_subscriptionType(ctx, field, obj) case "directives": out.Values[i] = ec.___Schema_directives(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } var __TypeImplementors = []string{"__Type"} func (ec *executionContext) ___Type(ctx context.Context, sel ast.SelectionSet, obj *introspection.Type) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, __TypeImplementors) out := graphql.NewFieldSet(fields) deferred := make(map[string]*graphql.FieldSet) for i, field := range fields { switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("__Type") case "kind": out.Values[i] = ec.___Type_kind(ctx, field, obj) if out.Values[i] == graphql.Null { out.Invalids++ } case "name": out.Values[i] = ec.___Type_name(ctx, field, obj) case "description": out.Values[i] = ec.___Type_description(ctx, field, obj) case "specifiedByURL": out.Values[i] = ec.___Type_specifiedByURL(ctx, field, obj) case "fields": out.Values[i] = ec.___Type_fields(ctx, field, obj) case "interfaces": out.Values[i] = ec.___Type_interfaces(ctx, field, obj) case "possibleTypes": out.Values[i] = ec.___Type_possibleTypes(ctx, field, obj) case "enumValues": out.Values[i] = ec.___Type_enumValues(ctx, field, obj) case "inputFields": out.Values[i] = ec.___Type_inputFields(ctx, field, obj) case "ofType": out.Values[i] = ec.___Type_ofType(ctx, field, obj) case "isOneOf": out.Values[i] = ec.___Type_isOneOf(ctx, field, obj) default: panic("unknown field " + strconv.Quote(field.Name)) } } out.Dispatch(ctx) if out.Invalids > 0 { return graphql.Null } atomic.AddInt32(&ec.Deferred, int32(len(deferred))) for label, dfs := range deferred { ec.ProcessDeferredGroup(graphql.DeferredGroup{ Label: label, Path: graphql.GetPath(ctx), FieldSet: dfs, Context: ctx, }) } return out } // endregion **************************** object.gotpl **************************** // region ***************************** type.gotpl ***************************** func (ec *executionContext) unmarshalNActivateNewUserInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐActivateNewUserInput(ctx context.Context, v any) (ActivateNewUserInput, error) { res, err := ec.unmarshalInputActivateNewUserInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNAmendEditInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐAmendEditInput(ctx context.Context, v any) (AmendEditInput, error) { res, err := ec.unmarshalInputAmendEditInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNAmendItemRemoval2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐAmendItemRemoval(ctx context.Context, v any) (AmendItemRemoval, error) { res, err := ec.unmarshalInputAmendItemRemoval(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNApplyEditInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐApplyEditInput(ctx context.Context, v any) (ApplyEditInput, error) { res, err := ec.unmarshalInputApplyEditInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNBodyModification2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐBodyModification(ctx context.Context, sel ast.SelectionSet, v BodyModification) graphql.Marshaler { return ec._BodyModification(ctx, sel, &v) } func (ec *executionContext) marshalNBodyModification2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐBodyModificationᚄ(ctx context.Context, sel ast.SelectionSet, v []BodyModification) graphql.Marshaler { ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNBodyModification2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐBodyModification(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) unmarshalNBodyModificationInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐBodyModificationInput(ctx context.Context, v any) (BodyModificationInput, error) { res, err := ec.unmarshalInputBodyModificationInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNBoolean2bool(ctx context.Context, v any) (bool, error) { res, err := graphql.UnmarshalBoolean(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNBoolean2bool(ctx context.Context, sel ast.SelectionSet, v bool) graphql.Marshaler { _ = sel res := graphql.MarshalBoolean(v) if res == graphql.Null { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } } return res } func (ec *executionContext) unmarshalNCancelEditInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐCancelEditInput(ctx context.Context, v any) (CancelEditInput, error) { res, err := ec.unmarshalInputCancelEditInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNCriterionModifier2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐCriterionModifier(ctx context.Context, v any) (CriterionModifier, error) { var res CriterionModifier err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNCriterionModifier2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐCriterionModifier(ctx context.Context, sel ast.SelectionSet, v CriterionModifier) graphql.Marshaler { return v } func (ec *executionContext) unmarshalNDate2string(ctx context.Context, v any) (string, error) { res, err := graphql.UnmarshalString(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNDate2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { _ = sel res := graphql.MarshalString(v) if res == graphql.Null { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } } return res } func (ec *executionContext) unmarshalNDateAccuracyEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDateAccuracyEnum(ctx context.Context, v any) (DateAccuracyEnum, error) { var res DateAccuracyEnum err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNDateAccuracyEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDateAccuracyEnum(ctx context.Context, sel ast.SelectionSet, v DateAccuracyEnum) graphql.Marshaler { return v } func (ec *executionContext) unmarshalNDeleteEditInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDeleteEditInput(ctx context.Context, v any) (DeleteEditInput, error) { res, err := ec.unmarshalInputDeleteEditInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNDeleteFingerprintSubmissionsInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDeleteFingerprintSubmissionsInput(ctx context.Context, v any) (DeleteFingerprintSubmissionsInput, error) { res, err := ec.unmarshalInputDeleteFingerprintSubmissionsInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNDraft2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDraft(ctx context.Context, sel ast.SelectionSet, v Draft) graphql.Marshaler { return ec._Draft(ctx, sel, &v) } func (ec *executionContext) marshalNDraft2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDraftᚄ(ctx context.Context, sel ast.SelectionSet, v []Draft) graphql.Marshaler { ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNDraft2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDraft(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) marshalNDraftData2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDraftData(ctx context.Context, sel ast.SelectionSet, v DraftData) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } return ec._DraftData(ctx, sel, v) } func (ec *executionContext) unmarshalNDraftEntityInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDraftEntityInput(ctx context.Context, v any) (DraftEntityInput, error) { res, err := ec.unmarshalInputDraftEntityInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNDraftEntityInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDraftEntityInputᚄ(ctx context.Context, v any) ([]DraftEntityInput, error) { var vSlice []any vSlice = graphql.CoerceList(v) var err error res := make([]DraftEntityInput, len(vSlice)) for i := range vSlice { ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) res[i], err = ec.unmarshalNDraftEntityInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDraftEntityInput(ctx, vSlice[i]) if err != nil { return nil, err } } return res, nil } func (ec *executionContext) marshalNDraftFingerprint2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDraftFingerprint(ctx context.Context, sel ast.SelectionSet, v DraftFingerprint) graphql.Marshaler { return ec._DraftFingerprint(ctx, sel, &v) } func (ec *executionContext) marshalNDraftFingerprint2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDraftFingerprintᚄ(ctx context.Context, sel ast.SelectionSet, v []DraftFingerprint) graphql.Marshaler { ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNDraftFingerprint2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDraftFingerprint(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) marshalNDraftSubmissionStatus2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDraftSubmissionStatus(ctx context.Context, sel ast.SelectionSet, v DraftSubmissionStatus) graphql.Marshaler { return ec._DraftSubmissionStatus(ctx, sel, &v) } func (ec *executionContext) marshalNDraftSubmissionStatus2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDraftSubmissionStatus(ctx context.Context, sel ast.SelectionSet, v *DraftSubmissionStatus) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } return ec._DraftSubmissionStatus(ctx, sel, v) } func (ec *executionContext) marshalNEdit2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEdit(ctx context.Context, sel ast.SelectionSet, v Edit) graphql.Marshaler { return ec._Edit(ctx, sel, &v) } func (ec *executionContext) marshalNEdit2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditᚄ(ctx context.Context, sel ast.SelectionSet, v []Edit) graphql.Marshaler { ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNEdit2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEdit(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) marshalNEdit2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEdit(ctx context.Context, sel ast.SelectionSet, v *Edit) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } return ec._Edit(ctx, sel, v) } func (ec *executionContext) marshalNEditComment2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditComment(ctx context.Context, sel ast.SelectionSet, v EditComment) graphql.Marshaler { return ec._EditComment(ctx, sel, &v) } func (ec *executionContext) marshalNEditComment2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditCommentᚄ(ctx context.Context, sel ast.SelectionSet, v []EditComment) graphql.Marshaler { ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNEditComment2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditComment(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) marshalNEditComment2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditComment(ctx context.Context, sel ast.SelectionSet, v *EditComment) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } return ec._EditComment(ctx, sel, v) } func (ec *executionContext) unmarshalNEditCommentInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditCommentInput(ctx context.Context, v any) (EditCommentInput, error) { res, err := ec.unmarshalInputEditCommentInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNEditInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditInput(ctx context.Context, v any) (*EditInput, error) { res, err := ec.unmarshalInputEditInput(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNEditQueryInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditQueryInput(ctx context.Context, v any) (EditQueryInput, error) { res, err := ec.unmarshalInputEditQueryInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNEditSortEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditSortEnum(ctx context.Context, v any) (EditSortEnum, error) { var res EditSortEnum err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNEditSortEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditSortEnum(ctx context.Context, sel ast.SelectionSet, v EditSortEnum) graphql.Marshaler { return v } func (ec *executionContext) marshalNEditTarget2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditTarget(ctx context.Context, sel ast.SelectionSet, v EditTarget) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } return ec._EditTarget(ctx, sel, v) } func (ec *executionContext) marshalNEditTarget2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditTargetᚄ(ctx context.Context, sel ast.SelectionSet, v []EditTarget) graphql.Marshaler { ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNEditTarget2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditTarget(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) marshalNEditVote2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditVote(ctx context.Context, sel ast.SelectionSet, v EditVote) graphql.Marshaler { return ec._EditVote(ctx, sel, &v) } func (ec *executionContext) marshalNEditVote2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditVoteᚄ(ctx context.Context, sel ast.SelectionSet, v []EditVote) graphql.Marshaler { ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNEditVote2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditVote(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) unmarshalNEditVoteInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditVoteInput(ctx context.Context, v any) (EditVoteInput, error) { res, err := ec.unmarshalInputEditVoteInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNFingerprint2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprint(ctx context.Context, sel ast.SelectionSet, v Fingerprint) graphql.Marshaler { return ec._Fingerprint(ctx, sel, &v) } func (ec *executionContext) marshalNFingerprint2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintᚄ(ctx context.Context, sel ast.SelectionSet, v []Fingerprint) graphql.Marshaler { ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNFingerprint2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprint(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) unmarshalNFingerprintAlgorithm2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintAlgorithm(ctx context.Context, v any) (FingerprintAlgorithm, error) { var res FingerprintAlgorithm err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNFingerprintAlgorithm2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintAlgorithm(ctx context.Context, sel ast.SelectionSet, v FingerprintAlgorithm) graphql.Marshaler { return v } func (ec *executionContext) unmarshalNFingerprintBatchSubmission2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintBatchSubmission(ctx context.Context, v any) (FingerprintBatchSubmission, error) { res, err := ec.unmarshalInputFingerprintBatchSubmission(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNFingerprintBatchSubmission2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintBatchSubmissionᚄ(ctx context.Context, v any) ([]FingerprintBatchSubmission, error) { var vSlice []any vSlice = graphql.CoerceList(v) var err error res := make([]FingerprintBatchSubmission, len(vSlice)) for i := range vSlice { ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) res[i], err = ec.unmarshalNFingerprintBatchSubmission2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintBatchSubmission(ctx, vSlice[i]) if err != nil { return nil, err } } return res, nil } func (ec *executionContext) unmarshalNFingerprintEditInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintEditInput(ctx context.Context, v any) (FingerprintEditInput, error) { res, err := ec.unmarshalInputFingerprintEditInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNFingerprintEditInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintEditInputᚄ(ctx context.Context, v any) ([]FingerprintEditInput, error) { var vSlice []any vSlice = graphql.CoerceList(v) var err error res := make([]FingerprintEditInput, len(vSlice)) for i := range vSlice { ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) res[i], err = ec.unmarshalNFingerprintEditInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintEditInput(ctx, vSlice[i]) if err != nil { return nil, err } } return res, nil } func (ec *executionContext) unmarshalNFingerprintHash2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintHash(ctx context.Context, v any) (FingerprintHash, error) { res, err := UnmarshalFingerprintHash(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNFingerprintHash2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintHash(ctx context.Context, sel ast.SelectionSet, v FingerprintHash) graphql.Marshaler { _ = sel res := MarshalFingerprintHash(v) if res == graphql.Null { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } } return res } func (ec *executionContext) unmarshalNFingerprintInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintInput(ctx context.Context, v any) (FingerprintInput, error) { res, err := ec.unmarshalInputFingerprintInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNFingerprintInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintInputᚄ(ctx context.Context, v any) ([]FingerprintInput, error) { var vSlice []any vSlice = graphql.CoerceList(v) var err error res := make([]FingerprintInput, len(vSlice)) for i := range vSlice { ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) res[i], err = ec.unmarshalNFingerprintInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintInput(ctx, vSlice[i]) if err != nil { return nil, err } } return res, nil } func (ec *executionContext) unmarshalNFingerprintInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintInput(ctx context.Context, v any) (*FingerprintInput, error) { res, err := ec.unmarshalInputFingerprintInput(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNFingerprintQueryInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintQueryInput(ctx context.Context, v any) (FingerprintQueryInput, error) { res, err := ec.unmarshalInputFingerprintQueryInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNFingerprintQueryInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintQueryInputᚄ(ctx context.Context, v any) ([]FingerprintQueryInput, error) { var vSlice []any vSlice = graphql.CoerceList(v) var err error res := make([]FingerprintQueryInput, len(vSlice)) for i := range vSlice { ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) res[i], err = ec.unmarshalNFingerprintQueryInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintQueryInput(ctx, vSlice[i]) if err != nil { return nil, err } } return res, nil } func (ec *executionContext) unmarshalNFingerprintQueryInput2ᚕᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintQueryInputᚄ(ctx context.Context, v any) ([][]FingerprintQueryInput, error) { var vSlice []any vSlice = graphql.CoerceList(v) var err error res := make([][]FingerprintQueryInput, len(vSlice)) for i := range vSlice { ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) res[i], err = ec.unmarshalNFingerprintQueryInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintQueryInputᚄ(ctx, vSlice[i]) if err != nil { return nil, err } } return res, nil } func (ec *executionContext) unmarshalNFingerprintSubmission2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintSubmission(ctx context.Context, v any) (FingerprintSubmission, error) { res, err := ec.unmarshalInputFingerprintSubmission(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNFingerprintSubmissionResult2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintSubmissionResult(ctx context.Context, sel ast.SelectionSet, v FingerprintSubmissionResult) graphql.Marshaler { return ec._FingerprintSubmissionResult(ctx, sel, &v) } func (ec *executionContext) marshalNFingerprintSubmissionResult2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintSubmissionResultᚄ(ctx context.Context, sel ast.SelectionSet, v []FingerprintSubmissionResult) graphql.Marshaler { ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNFingerprintSubmissionResult2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintSubmissionResult(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) unmarshalNGenderEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐGenderEnum(ctx context.Context, v any) (GenderEnum, error) { var res GenderEnum err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNGenderEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐGenderEnum(ctx context.Context, sel ast.SelectionSet, v GenderEnum) graphql.Marshaler { return v } func (ec *executionContext) marshalNGenderFacet2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐGenderFacet(ctx context.Context, sel ast.SelectionSet, v GenderFacet) graphql.Marshaler { return ec._GenderFacet(ctx, sel, &v) } func (ec *executionContext) marshalNGenderFacet2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐGenderFacetᚄ(ctx context.Context, sel ast.SelectionSet, v []GenderFacet) graphql.Marshaler { ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNGenderFacet2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐGenderFacet(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) unmarshalNGrantInviteInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐGrantInviteInput(ctx context.Context, v any) (GrantInviteInput, error) { res, err := ec.unmarshalInputGrantInviteInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx context.Context, v any) (uuid.UUID, error) { res, err := UnmarshalID(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx context.Context, sel ast.SelectionSet, v uuid.UUID) graphql.Marshaler { _ = sel res := MarshalID(v) if res == graphql.Null { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } } return res } func (ec *executionContext) unmarshalNID2ᚕgithubᚗcomᚋgofrsᚋuuidᚐUUIDᚄ(ctx context.Context, v any) ([]uuid.UUID, error) { var vSlice []any vSlice = graphql.CoerceList(v) var err error res := make([]uuid.UUID, len(vSlice)) for i := range vSlice { ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) res[i], err = ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, vSlice[i]) if err != nil { return nil, err } } return res, nil } func (ec *executionContext) marshalNID2ᚕgithubᚗcomᚋgofrsᚋuuidᚐUUIDᚄ(ctx context.Context, sel ast.SelectionSet, v []uuid.UUID) graphql.Marshaler { ret := make(graphql.Array, len(v)) for i := range v { ret[i] = ec.marshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, sel, v[i]) } for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) marshalNImage2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐImage(ctx context.Context, sel ast.SelectionSet, v Image) graphql.Marshaler { return ec._Image(ctx, sel, &v) } func (ec *executionContext) marshalNImage2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐImageᚄ(ctx context.Context, sel ast.SelectionSet, v []Image) graphql.Marshaler { ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNImage2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐImage(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) unmarshalNImageCreateInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐImageCreateInput(ctx context.Context, v any) (ImageCreateInput, error) { res, err := ec.unmarshalInputImageCreateInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNImageDestroyInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐImageDestroyInput(ctx context.Context, v any) (ImageDestroyInput, error) { res, err := ec.unmarshalInputImageDestroyInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNInt2int(ctx context.Context, v any) (int, error) { res, err := graphql.UnmarshalInt(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNInt2int(ctx context.Context, sel ast.SelectionSet, v int) graphql.Marshaler { _ = sel res := graphql.MarshalInt(v) if res == graphql.Null { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } } return res } func (ec *executionContext) unmarshalNInt2ᚕintᚄ(ctx context.Context, v any) ([]int, error) { var vSlice []any vSlice = graphql.CoerceList(v) var err error res := make([]int, len(vSlice)) for i := range vSlice { ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) res[i], err = ec.unmarshalNInt2int(ctx, vSlice[i]) if err != nil { return nil, err } } return res, nil } func (ec *executionContext) marshalNInt2ᚕintᚄ(ctx context.Context, sel ast.SelectionSet, v []int) graphql.Marshaler { ret := make(graphql.Array, len(v)) for i := range v { ret[i] = ec.marshalNInt2int(ctx, sel, v[i]) } for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) marshalNInviteKey2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐInviteKey(ctx context.Context, sel ast.SelectionSet, v InviteKey) graphql.Marshaler { return ec._InviteKey(ctx, sel, &v) } func (ec *executionContext) marshalNMeasurements2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐMeasurements(ctx context.Context, sel ast.SelectionSet, v Measurements) graphql.Marshaler { return ec._Measurements(ctx, sel, &v) } func (ec *executionContext) marshalNMeasurements2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐMeasurements(ctx context.Context, sel ast.SelectionSet, v *Measurements) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } return ec._Measurements(ctx, sel, v) } func (ec *executionContext) marshalNModAudit2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐModAudit(ctx context.Context, sel ast.SelectionSet, v ModAudit) graphql.Marshaler { return ec._ModAudit(ctx, sel, &v) } func (ec *executionContext) marshalNModAudit2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐModAuditᚄ(ctx context.Context, sel ast.SelectionSet, v []ModAudit) graphql.Marshaler { ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNModAudit2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐModAudit(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) unmarshalNModAuditActionEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐModAuditActionEnum(ctx context.Context, v any) (ModAuditActionEnum, error) { var res ModAuditActionEnum err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNModAuditActionEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐModAuditActionEnum(ctx context.Context, sel ast.SelectionSet, v ModAuditActionEnum) graphql.Marshaler { return v } func (ec *executionContext) unmarshalNModAuditQueryInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐModAuditQueryInput(ctx context.Context, v any) (ModAuditQueryInput, error) { res, err := ec.unmarshalInputModAuditQueryInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNMoveFingerprintSubmissionsInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐMoveFingerprintSubmissionsInput(ctx context.Context, v any) (MoveFingerprintSubmissionsInput, error) { res, err := ec.unmarshalInputMoveFingerprintSubmissionsInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNNewUserInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐNewUserInput(ctx context.Context, v any) (NewUserInput, error) { res, err := ec.unmarshalInputNewUserInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNNotification2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐNotification(ctx context.Context, sel ast.SelectionSet, v Notification) graphql.Marshaler { return ec._Notification(ctx, sel, &v) } func (ec *executionContext) marshalNNotification2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐNotificationᚄ(ctx context.Context, sel ast.SelectionSet, v []Notification) graphql.Marshaler { ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNNotification2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐNotification(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) marshalNNotificationData2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐNotificationData(ctx context.Context, sel ast.SelectionSet, v NotificationData) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } return ec._NotificationData(ctx, sel, v) } func (ec *executionContext) unmarshalNNotificationEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐNotificationEnum(ctx context.Context, v any) (NotificationEnum, error) { var res NotificationEnum err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNNotificationEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐNotificationEnum(ctx context.Context, sel ast.SelectionSet, v NotificationEnum) graphql.Marshaler { return v } func (ec *executionContext) unmarshalNNotificationEnum2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐNotificationEnumᚄ(ctx context.Context, v any) ([]NotificationEnum, error) { var vSlice []any vSlice = graphql.CoerceList(v) var err error res := make([]NotificationEnum, len(vSlice)) for i := range vSlice { ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) res[i], err = ec.unmarshalNNotificationEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐNotificationEnum(ctx, vSlice[i]) if err != nil { return nil, err } } return res, nil } func (ec *executionContext) marshalNNotificationEnum2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐNotificationEnumᚄ(ctx context.Context, sel ast.SelectionSet, v []NotificationEnum) graphql.Marshaler { ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNNotificationEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐNotificationEnum(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) unmarshalNOperationEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐOperationEnum(ctx context.Context, v any) (OperationEnum, error) { var res OperationEnum err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNOperationEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐOperationEnum(ctx context.Context, sel ast.SelectionSet, v OperationEnum) graphql.Marshaler { return v } func (ec *executionContext) marshalNPerformer2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformer(ctx context.Context, sel ast.SelectionSet, v Performer) graphql.Marshaler { return ec._Performer(ctx, sel, &v) } func (ec *executionContext) marshalNPerformer2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerᚄ(ctx context.Context, sel ast.SelectionSet, v []Performer) graphql.Marshaler { ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNPerformer2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformer(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) marshalNPerformer2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformer(ctx context.Context, sel ast.SelectionSet, v *Performer) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } return ec._Performer(ctx, sel, v) } func (ec *executionContext) marshalNPerformerAppearance2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerAppearance(ctx context.Context, sel ast.SelectionSet, v PerformerAppearance) graphql.Marshaler { return ec._PerformerAppearance(ctx, sel, &v) } func (ec *executionContext) marshalNPerformerAppearance2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerAppearanceᚄ(ctx context.Context, sel ast.SelectionSet, v []PerformerAppearance) graphql.Marshaler { ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNPerformerAppearance2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerAppearance(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) unmarshalNPerformerAppearanceInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerAppearanceInput(ctx context.Context, v any) (PerformerAppearanceInput, error) { res, err := ec.unmarshalInputPerformerAppearanceInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNPerformerCreateInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerCreateInput(ctx context.Context, v any) (PerformerCreateInput, error) { res, err := ec.unmarshalInputPerformerCreateInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNPerformerDestroyInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerDestroyInput(ctx context.Context, v any) (PerformerDestroyInput, error) { res, err := ec.unmarshalInputPerformerDestroyInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNPerformerDraftInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerDraftInput(ctx context.Context, v any) (PerformerDraftInput, error) { res, err := ec.unmarshalInputPerformerDraftInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNPerformerEditInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerEditInput(ctx context.Context, v any) (PerformerEditInput, error) { res, err := ec.unmarshalInputPerformerEditInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNPerformerQueryInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerQueryInput(ctx context.Context, v any) (PerformerQueryInput, error) { res, err := ec.unmarshalInputPerformerQueryInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNPerformerSortEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerSortEnum(ctx context.Context, v any) (PerformerSortEnum, error) { var res PerformerSortEnum err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNPerformerSortEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerSortEnum(ctx context.Context, sel ast.SelectionSet, v PerformerSortEnum) graphql.Marshaler { return v } func (ec *executionContext) marshalNPerformerStudio2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerStudio(ctx context.Context, sel ast.SelectionSet, v PerformerStudio) graphql.Marshaler { return ec._PerformerStudio(ctx, sel, &v) } func (ec *executionContext) marshalNPerformerStudio2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerStudioᚄ(ctx context.Context, sel ast.SelectionSet, v []PerformerStudio) graphql.Marshaler { ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNPerformerStudio2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerStudio(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) unmarshalNPerformerUpdateInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerUpdateInput(ctx context.Context, v any) (PerformerUpdateInput, error) { res, err := ec.unmarshalInputPerformerUpdateInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNQueryEditsResultType2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditQuery(ctx context.Context, sel ast.SelectionSet, v EditQuery) graphql.Marshaler { return ec._QueryEditsResultType(ctx, sel, &v) } func (ec *executionContext) marshalNQueryEditsResultType2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditQuery(ctx context.Context, sel ast.SelectionSet, v *EditQuery) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } return ec._QueryEditsResultType(ctx, sel, v) } func (ec *executionContext) unmarshalNQueryExistingPerformerInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐQueryExistingPerformerInput(ctx context.Context, v any) (QueryExistingPerformerInput, error) { res, err := ec.unmarshalInputQueryExistingPerformerInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNQueryExistingPerformerResult2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐQueryExistingPerformerResult(ctx context.Context, sel ast.SelectionSet, v QueryExistingPerformerResult) graphql.Marshaler { return ec._QueryExistingPerformerResult(ctx, sel, &v) } func (ec *executionContext) marshalNQueryExistingPerformerResult2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐQueryExistingPerformerResult(ctx context.Context, sel ast.SelectionSet, v *QueryExistingPerformerResult) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } return ec._QueryExistingPerformerResult(ctx, sel, v) } func (ec *executionContext) unmarshalNQueryExistingSceneInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐQueryExistingSceneInput(ctx context.Context, v any) (QueryExistingSceneInput, error) { res, err := ec.unmarshalInputQueryExistingSceneInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNQueryExistingSceneResult2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐQueryExistingSceneResult(ctx context.Context, sel ast.SelectionSet, v QueryExistingSceneResult) graphql.Marshaler { return ec._QueryExistingSceneResult(ctx, sel, &v) } func (ec *executionContext) marshalNQueryExistingSceneResult2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐQueryExistingSceneResult(ctx context.Context, sel ast.SelectionSet, v *QueryExistingSceneResult) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } return ec._QueryExistingSceneResult(ctx, sel, v) } func (ec *executionContext) marshalNQueryModAuditsResultType2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐModAuditQuery(ctx context.Context, sel ast.SelectionSet, v ModAuditQuery) graphql.Marshaler { return ec._QueryModAuditsResultType(ctx, sel, &v) } func (ec *executionContext) marshalNQueryModAuditsResultType2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐModAuditQuery(ctx context.Context, sel ast.SelectionSet, v *ModAuditQuery) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } return ec._QueryModAuditsResultType(ctx, sel, v) } func (ec *executionContext) unmarshalNQueryNotificationsInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐQueryNotificationsInput(ctx context.Context, v any) (QueryNotificationsInput, error) { res, err := ec.unmarshalInputQueryNotificationsInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNQueryNotificationsResult2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐQueryNotificationsResult(ctx context.Context, sel ast.SelectionSet, v QueryNotificationsResult) graphql.Marshaler { return ec._QueryNotificationsResult(ctx, sel, &v) } func (ec *executionContext) marshalNQueryNotificationsResult2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐQueryNotificationsResult(ctx context.Context, sel ast.SelectionSet, v *QueryNotificationsResult) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } return ec._QueryNotificationsResult(ctx, sel, v) } func (ec *executionContext) marshalNQueryPerformersResultType2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerQuery(ctx context.Context, sel ast.SelectionSet, v PerformerQuery) graphql.Marshaler { return ec._QueryPerformersResultType(ctx, sel, &v) } func (ec *executionContext) marshalNQueryPerformersResultType2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerQuery(ctx context.Context, sel ast.SelectionSet, v *PerformerQuery) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } return ec._QueryPerformersResultType(ctx, sel, v) } func (ec *executionContext) marshalNQueryScenesResultType2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneQuery(ctx context.Context, sel ast.SelectionSet, v SceneQuery) graphql.Marshaler { return ec._QueryScenesResultType(ctx, sel, &v) } func (ec *executionContext) marshalNQueryScenesResultType2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneQuery(ctx context.Context, sel ast.SelectionSet, v *SceneQuery) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } return ec._QueryScenesResultType(ctx, sel, v) } func (ec *executionContext) marshalNQuerySitesResultType2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐQuerySitesResultType(ctx context.Context, sel ast.SelectionSet, v QuerySitesResultType) graphql.Marshaler { return ec._QuerySitesResultType(ctx, sel, &v) } func (ec *executionContext) marshalNQuerySitesResultType2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐQuerySitesResultType(ctx context.Context, sel ast.SelectionSet, v *QuerySitesResultType) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } return ec._QuerySitesResultType(ctx, sel, v) } func (ec *executionContext) marshalNQueryStudiosResultType2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐQueryStudiosResultType(ctx context.Context, sel ast.SelectionSet, v QueryStudiosResultType) graphql.Marshaler { return ec._QueryStudiosResultType(ctx, sel, &v) } func (ec *executionContext) marshalNQueryStudiosResultType2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐQueryStudiosResultType(ctx context.Context, sel ast.SelectionSet, v *QueryStudiosResultType) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } return ec._QueryStudiosResultType(ctx, sel, v) } func (ec *executionContext) marshalNQueryTagCategoriesResultType2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐQueryTagCategoriesResultType(ctx context.Context, sel ast.SelectionSet, v QueryTagCategoriesResultType) graphql.Marshaler { return ec._QueryTagCategoriesResultType(ctx, sel, &v) } func (ec *executionContext) marshalNQueryTagCategoriesResultType2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐQueryTagCategoriesResultType(ctx context.Context, sel ast.SelectionSet, v *QueryTagCategoriesResultType) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } return ec._QueryTagCategoriesResultType(ctx, sel, v) } func (ec *executionContext) marshalNQueryTagsResultType2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐQueryTagsResultType(ctx context.Context, sel ast.SelectionSet, v QueryTagsResultType) graphql.Marshaler { return ec._QueryTagsResultType(ctx, sel, &v) } func (ec *executionContext) marshalNQueryTagsResultType2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐQueryTagsResultType(ctx context.Context, sel ast.SelectionSet, v *QueryTagsResultType) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } return ec._QueryTagsResultType(ctx, sel, v) } func (ec *executionContext) marshalNQueryUsersResultType2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐQueryUsersResultType(ctx context.Context, sel ast.SelectionSet, v QueryUsersResultType) graphql.Marshaler { return ec._QueryUsersResultType(ctx, sel, &v) } func (ec *executionContext) marshalNQueryUsersResultType2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐQueryUsersResultType(ctx context.Context, sel ast.SelectionSet, v *QueryUsersResultType) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } return ec._QueryUsersResultType(ctx, sel, v) } func (ec *executionContext) unmarshalNResetPasswordInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐResetPasswordInput(ctx context.Context, v any) (ResetPasswordInput, error) { res, err := ec.unmarshalInputResetPasswordInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNRevokeInviteInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRevokeInviteInput(ctx context.Context, v any) (RevokeInviteInput, error) { res, err := ec.unmarshalInputRevokeInviteInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx context.Context, v any) (RoleEnum, error) { var res RoleEnum err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx context.Context, sel ast.SelectionSet, v RoleEnum) graphql.Marshaler { return v } func (ec *executionContext) unmarshalNRoleEnum2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnumᚄ(ctx context.Context, v any) ([]RoleEnum, error) { var vSlice []any vSlice = graphql.CoerceList(v) var err error res := make([]RoleEnum, len(vSlice)) for i := range vSlice { ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) res[i], err = ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, vSlice[i]) if err != nil { return nil, err } } return res, nil } func (ec *executionContext) marshalNRoleEnum2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnumᚄ(ctx context.Context, sel ast.SelectionSet, v []RoleEnum) graphql.Marshaler { ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) marshalNScene2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐScene(ctx context.Context, sel ast.SelectionSet, v Scene) graphql.Marshaler { return ec._Scene(ctx, sel, &v) } func (ec *executionContext) marshalNScene2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneᚄ(ctx context.Context, sel ast.SelectionSet, v []Scene) graphql.Marshaler { ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNScene2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐScene(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) marshalNScene2ᚕᚕᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneᚄ(ctx context.Context, sel ast.SelectionSet, v [][]*Scene) graphql.Marshaler { ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNScene2ᚕᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐScene(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) marshalNScene2ᚕᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐScene(ctx context.Context, sel ast.SelectionSet, v []*Scene) graphql.Marshaler { ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalOScene2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐScene(ctx, sel, v[i]) }) return ret } func (ec *executionContext) marshalNScene2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐScene(ctx context.Context, sel ast.SelectionSet, v *Scene) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } return ec._Scene(ctx, sel, v) } func (ec *executionContext) unmarshalNSceneCreateInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneCreateInput(ctx context.Context, v any) (SceneCreateInput, error) { res, err := ec.unmarshalInputSceneCreateInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNSceneDestroyInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneDestroyInput(ctx context.Context, v any) (SceneDestroyInput, error) { res, err := ec.unmarshalInputSceneDestroyInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNSceneDraftInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneDraftInput(ctx context.Context, v any) (SceneDraftInput, error) { res, err := ec.unmarshalInputSceneDraftInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNSceneDraftPerformer2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneDraftPerformer(ctx context.Context, sel ast.SelectionSet, v SceneDraftPerformer) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } return ec._SceneDraftPerformer(ctx, sel, v) } func (ec *executionContext) marshalNSceneDraftPerformer2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneDraftPerformerᚄ(ctx context.Context, sel ast.SelectionSet, v []SceneDraftPerformer) graphql.Marshaler { ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNSceneDraftPerformer2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneDraftPerformer(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) marshalNSceneDraftTag2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneDraftTag(ctx context.Context, sel ast.SelectionSet, v SceneDraftTag) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } return ec._SceneDraftTag(ctx, sel, v) } func (ec *executionContext) unmarshalNSceneEditInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneEditInput(ctx context.Context, v any) (SceneEditInput, error) { res, err := ec.unmarshalInputSceneEditInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNSceneQueryInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneQueryInput(ctx context.Context, v any) (SceneQueryInput, error) { res, err := ec.unmarshalInputSceneQueryInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNSceneSortEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneSortEnum(ctx context.Context, v any) (SceneSortEnum, error) { var res SceneSortEnum err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNSceneSortEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneSortEnum(ctx context.Context, sel ast.SelectionSet, v SceneSortEnum) graphql.Marshaler { return v } func (ec *executionContext) unmarshalNSceneUpdateInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneUpdateInput(ctx context.Context, v any) (SceneUpdateInput, error) { res, err := ec.unmarshalInputSceneUpdateInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNSite2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSite(ctx context.Context, sel ast.SelectionSet, v Site) graphql.Marshaler { return ec._Site(ctx, sel, &v) } func (ec *executionContext) marshalNSite2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSiteᚄ(ctx context.Context, sel ast.SelectionSet, v []Site) graphql.Marshaler { ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNSite2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSite(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) marshalNSite2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSite(ctx context.Context, sel ast.SelectionSet, v *Site) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } return ec._Site(ctx, sel, v) } func (ec *executionContext) unmarshalNSiteCreateInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSiteCreateInput(ctx context.Context, v any) (SiteCreateInput, error) { res, err := ec.unmarshalInputSiteCreateInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNSiteDestroyInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSiteDestroyInput(ctx context.Context, v any) (SiteDestroyInput, error) { res, err := ec.unmarshalInputSiteDestroyInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNSiteUpdateInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSiteUpdateInput(ctx context.Context, v any) (SiteUpdateInput, error) { res, err := ec.unmarshalInputSiteUpdateInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNSortDirectionEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSortDirectionEnum(ctx context.Context, v any) (SortDirectionEnum, error) { var res SortDirectionEnum err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNSortDirectionEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSortDirectionEnum(ctx context.Context, sel ast.SelectionSet, v SortDirectionEnum) graphql.Marshaler { return v } func (ec *executionContext) marshalNStashBoxConfig2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStashBoxConfig(ctx context.Context, sel ast.SelectionSet, v StashBoxConfig) graphql.Marshaler { return ec._StashBoxConfig(ctx, sel, &v) } func (ec *executionContext) marshalNStashBoxConfig2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStashBoxConfig(ctx context.Context, sel ast.SelectionSet, v *StashBoxConfig) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } return ec._StashBoxConfig(ctx, sel, v) } func (ec *executionContext) unmarshalNString2string(ctx context.Context, v any) (string, error) { res, err := graphql.UnmarshalString(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNString2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { _ = sel res := graphql.MarshalString(v) if res == graphql.Null { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } } return res } func (ec *executionContext) unmarshalNString2ᚕstringᚄ(ctx context.Context, v any) ([]string, error) { var vSlice []any vSlice = graphql.CoerceList(v) var err error res := make([]string, len(vSlice)) for i := range vSlice { ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) res[i], err = ec.unmarshalNString2string(ctx, vSlice[i]) if err != nil { return nil, err } } return res, nil } func (ec *executionContext) marshalNString2ᚕstringᚄ(ctx context.Context, sel ast.SelectionSet, v []string) graphql.Marshaler { ret := make(graphql.Array, len(v)) for i := range v { ret[i] = ec.marshalNString2string(ctx, sel, v[i]) } for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) marshalNStudio2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStudio(ctx context.Context, sel ast.SelectionSet, v Studio) graphql.Marshaler { return ec._Studio(ctx, sel, &v) } func (ec *executionContext) marshalNStudio2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStudioᚄ(ctx context.Context, sel ast.SelectionSet, v []Studio) graphql.Marshaler { ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNStudio2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStudio(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) marshalNStudio2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStudio(ctx context.Context, sel ast.SelectionSet, v *Studio) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } return ec._Studio(ctx, sel, v) } func (ec *executionContext) unmarshalNStudioCreateInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStudioCreateInput(ctx context.Context, v any) (StudioCreateInput, error) { res, err := ec.unmarshalInputStudioCreateInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNStudioDestroyInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStudioDestroyInput(ctx context.Context, v any) (StudioDestroyInput, error) { res, err := ec.unmarshalInputStudioDestroyInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNStudioEditInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStudioEditInput(ctx context.Context, v any) (StudioEditInput, error) { res, err := ec.unmarshalInputStudioEditInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNStudioQueryInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStudioQueryInput(ctx context.Context, v any) (StudioQueryInput, error) { res, err := ec.unmarshalInputStudioQueryInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNStudioSortEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStudioSortEnum(ctx context.Context, v any) (StudioSortEnum, error) { var res StudioSortEnum err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNStudioSortEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStudioSortEnum(ctx context.Context, sel ast.SelectionSet, v StudioSortEnum) graphql.Marshaler { return v } func (ec *executionContext) unmarshalNStudioUpdateInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStudioUpdateInput(ctx context.Context, v any) (StudioUpdateInput, error) { res, err := ec.unmarshalInputStudioUpdateInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNTag2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTag(ctx context.Context, sel ast.SelectionSet, v Tag) graphql.Marshaler { return ec._Tag(ctx, sel, &v) } func (ec *executionContext) marshalNTag2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagᚄ(ctx context.Context, sel ast.SelectionSet, v []Tag) graphql.Marshaler { ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNTag2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTag(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) marshalNTagCategory2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagCategory(ctx context.Context, sel ast.SelectionSet, v TagCategory) graphql.Marshaler { return ec._TagCategory(ctx, sel, &v) } func (ec *executionContext) marshalNTagCategory2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagCategoryᚄ(ctx context.Context, sel ast.SelectionSet, v []TagCategory) graphql.Marshaler { ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNTagCategory2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagCategory(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) unmarshalNTagCategoryCreateInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagCategoryCreateInput(ctx context.Context, v any) (TagCategoryCreateInput, error) { res, err := ec.unmarshalInputTagCategoryCreateInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNTagCategoryDestroyInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagCategoryDestroyInput(ctx context.Context, v any) (TagCategoryDestroyInput, error) { res, err := ec.unmarshalInputTagCategoryDestroyInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNTagCategoryUpdateInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagCategoryUpdateInput(ctx context.Context, v any) (TagCategoryUpdateInput, error) { res, err := ec.unmarshalInputTagCategoryUpdateInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNTagCreateInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagCreateInput(ctx context.Context, v any) (TagCreateInput, error) { res, err := ec.unmarshalInputTagCreateInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNTagDestroyInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagDestroyInput(ctx context.Context, v any) (TagDestroyInput, error) { res, err := ec.unmarshalInputTagDestroyInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNTagEditInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagEditInput(ctx context.Context, v any) (TagEditInput, error) { res, err := ec.unmarshalInputTagEditInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNTagGroupEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagGroupEnum(ctx context.Context, v any) (TagGroupEnum, error) { var res TagGroupEnum err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNTagGroupEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagGroupEnum(ctx context.Context, sel ast.SelectionSet, v TagGroupEnum) graphql.Marshaler { return v } func (ec *executionContext) unmarshalNTagQueryInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagQueryInput(ctx context.Context, v any) (TagQueryInput, error) { res, err := ec.unmarshalInputTagQueryInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNTagSortEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagSortEnum(ctx context.Context, v any) (TagSortEnum, error) { var res TagSortEnum err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNTagSortEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagSortEnum(ctx context.Context, sel ast.SelectionSet, v TagSortEnum) graphql.Marshaler { return v } func (ec *executionContext) unmarshalNTagUpdateInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagUpdateInput(ctx context.Context, v any) (TagUpdateInput, error) { res, err := ec.unmarshalInputTagUpdateInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNTargetTypeEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTargetTypeEnum(ctx context.Context, v any) (TargetTypeEnum, error) { var res TargetTypeEnum err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNTargetTypeEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTargetTypeEnum(ctx context.Context, sel ast.SelectionSet, v TargetTypeEnum) graphql.Marshaler { return v } func (ec *executionContext) unmarshalNTime2timeᚐTime(ctx context.Context, v any) (time.Time, error) { res, err := graphql.UnmarshalTime(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNTime2timeᚐTime(ctx context.Context, sel ast.SelectionSet, v time.Time) graphql.Marshaler { _ = sel res := graphql.MarshalTime(v) if res == graphql.Null { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } } return res } func (ec *executionContext) unmarshalNTime2ᚖtimeᚐTime(ctx context.Context, v any) (*time.Time, error) { res, err := graphql.UnmarshalTime(v) return &res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNTime2ᚖtimeᚐTime(ctx context.Context, sel ast.SelectionSet, v *time.Time) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } _ = sel res := graphql.MarshalTime(*v) if res == graphql.Null { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } } return res } func (ec *executionContext) marshalNURL2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐURL(ctx context.Context, sel ast.SelectionSet, v URL) graphql.Marshaler { return ec._URL(ctx, sel, &v) } func (ec *executionContext) marshalNURL2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐURLᚄ(ctx context.Context, sel ast.SelectionSet, v []URL) graphql.Marshaler { ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNURL2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐURL(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) unmarshalNURLInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐURL(ctx context.Context, v any) (URL, error) { res, err := ec.unmarshalInputURLInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNUser2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUser(ctx context.Context, sel ast.SelectionSet, v User) graphql.Marshaler { return ec._User(ctx, sel, &v) } func (ec *executionContext) marshalNUser2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUserᚄ(ctx context.Context, sel ast.SelectionSet, v []User) graphql.Marshaler { ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNUser2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUser(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) unmarshalNUserChangeEmailStatus2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUserChangeEmailStatus(ctx context.Context, v any) (UserChangeEmailStatus, error) { var res UserChangeEmailStatus err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNUserChangeEmailStatus2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUserChangeEmailStatus(ctx context.Context, sel ast.SelectionSet, v UserChangeEmailStatus) graphql.Marshaler { return v } func (ec *executionContext) unmarshalNUserChangePasswordInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUserChangePasswordInput(ctx context.Context, v any) (UserChangePasswordInput, error) { res, err := ec.unmarshalInputUserChangePasswordInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNUserCreateInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUserCreateInput(ctx context.Context, v any) (UserCreateInput, error) { res, err := ec.unmarshalInputUserCreateInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNUserDestroyInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUserDestroyInput(ctx context.Context, v any) (UserDestroyInput, error) { res, err := ec.unmarshalInputUserDestroyInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNUserEditCount2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUserEditCount(ctx context.Context, sel ast.SelectionSet, v UserEditCount) graphql.Marshaler { return ec._UserEditCount(ctx, sel, &v) } func (ec *executionContext) marshalNUserEditCount2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUserEditCount(ctx context.Context, sel ast.SelectionSet, v *UserEditCount) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } return ec._UserEditCount(ctx, sel, v) } func (ec *executionContext) unmarshalNUserQueryInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUserQueryInput(ctx context.Context, v any) (UserQueryInput, error) { res, err := ec.unmarshalInputUserQueryInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalNUserUpdateInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUserUpdateInput(ctx context.Context, v any) (UserUpdateInput, error) { res, err := ec.unmarshalInputUserUpdateInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNUserVoteCount2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUserVoteCount(ctx context.Context, sel ast.SelectionSet, v UserVoteCount) graphql.Marshaler { return ec._UserVoteCount(ctx, sel, &v) } func (ec *executionContext) marshalNUserVoteCount2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUserVoteCount(ctx context.Context, sel ast.SelectionSet, v *UserVoteCount) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } return ec._UserVoteCount(ctx, sel, v) } func (ec *executionContext) unmarshalNValidSiteTypeEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐValidSiteTypeEnum(ctx context.Context, v any) (ValidSiteTypeEnum, error) { var res ValidSiteTypeEnum err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNValidSiteTypeEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐValidSiteTypeEnum(ctx context.Context, sel ast.SelectionSet, v ValidSiteTypeEnum) graphql.Marshaler { return v } func (ec *executionContext) unmarshalNValidSiteTypeEnum2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐValidSiteTypeEnumᚄ(ctx context.Context, v any) ([]ValidSiteTypeEnum, error) { var vSlice []any vSlice = graphql.CoerceList(v) var err error res := make([]ValidSiteTypeEnum, len(vSlice)) for i := range vSlice { ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) res[i], err = ec.unmarshalNValidSiteTypeEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐValidSiteTypeEnum(ctx, vSlice[i]) if err != nil { return nil, err } } return res, nil } func (ec *executionContext) marshalNValidSiteTypeEnum2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐValidSiteTypeEnumᚄ(ctx context.Context, sel ast.SelectionSet, v []ValidSiteTypeEnum) graphql.Marshaler { ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNValidSiteTypeEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐValidSiteTypeEnum(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) marshalNVersion2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐVersion(ctx context.Context, sel ast.SelectionSet, v Version) graphql.Marshaler { return ec._Version(ctx, sel, &v) } func (ec *executionContext) marshalNVersion2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐVersion(ctx context.Context, sel ast.SelectionSet, v *Version) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } return ec._Version(ctx, sel, v) } func (ec *executionContext) unmarshalNVoteStatusEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐVoteStatusEnum(ctx context.Context, v any) (VoteStatusEnum, error) { var res VoteStatusEnum err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNVoteStatusEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐVoteStatusEnum(ctx context.Context, sel ast.SelectionSet, v VoteStatusEnum) graphql.Marshaler { return v } func (ec *executionContext) unmarshalNVoteTypeEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐVoteTypeEnum(ctx context.Context, v any) (VoteTypeEnum, error) { var res VoteTypeEnum err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalNVoteTypeEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐVoteTypeEnum(ctx context.Context, sel ast.SelectionSet, v VoteTypeEnum) graphql.Marshaler { return v } func (ec *executionContext) marshalN__Directive2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirective(ctx context.Context, sel ast.SelectionSet, v introspection.Directive) graphql.Marshaler { return ec.___Directive(ctx, sel, &v) } func (ec *executionContext) marshalN__Directive2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirectiveᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Directive) graphql.Marshaler { ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalN__Directive2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirective(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) unmarshalN__DirectiveLocation2string(ctx context.Context, v any) (string, error) { res, err := graphql.UnmarshalString(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalN__DirectiveLocation2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { _ = sel res := graphql.MarshalString(v) if res == graphql.Null { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } } return res } func (ec *executionContext) unmarshalN__DirectiveLocation2ᚕstringᚄ(ctx context.Context, v any) ([]string, error) { var vSlice []any vSlice = graphql.CoerceList(v) var err error res := make([]string, len(vSlice)) for i := range vSlice { ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) res[i], err = ec.unmarshalN__DirectiveLocation2string(ctx, vSlice[i]) if err != nil { return nil, err } } return res, nil } func (ec *executionContext) marshalN__DirectiveLocation2ᚕstringᚄ(ctx context.Context, sel ast.SelectionSet, v []string) graphql.Marshaler { ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalN__DirectiveLocation2string(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) marshalN__EnumValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValue(ctx context.Context, sel ast.SelectionSet, v introspection.EnumValue) graphql.Marshaler { return ec.___EnumValue(ctx, sel, &v) } func (ec *executionContext) marshalN__Field2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐField(ctx context.Context, sel ast.SelectionSet, v introspection.Field) graphql.Marshaler { return ec.___Field(ctx, sel, &v) } func (ec *executionContext) marshalN__InputValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValue(ctx context.Context, sel ast.SelectionSet, v introspection.InputValue) graphql.Marshaler { return ec.___InputValue(ctx, sel, &v) } func (ec *executionContext) marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.InputValue) graphql.Marshaler { ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalN__InputValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValue(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) marshalN__Type2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx context.Context, sel ast.SelectionSet, v introspection.Type) graphql.Marshaler { return ec.___Type(ctx, sel, &v) } func (ec *executionContext) marshalN__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Type) graphql.Marshaler { ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalN__Type2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx context.Context, sel ast.SelectionSet, v *introspection.Type) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } return graphql.Null } return ec.___Type(ctx, sel, v) } func (ec *executionContext) unmarshalN__TypeKind2string(ctx context.Context, v any) (string, error) { res, err := graphql.UnmarshalString(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalN__TypeKind2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { _ = sel res := graphql.MarshalString(v) if res == graphql.Null { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") } } return res } func (ec *executionContext) unmarshalOAmendItemRemoval2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐAmendItemRemovalᚄ(ctx context.Context, v any) ([]AmendItemRemoval, error) { if v == nil { return nil, nil } var vSlice []any vSlice = graphql.CoerceList(v) var err error res := make([]AmendItemRemoval, len(vSlice)) for i := range vSlice { ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) res[i], err = ec.unmarshalNAmendItemRemoval2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐAmendItemRemoval(ctx, vSlice[i]) if err != nil { return nil, err } } return res, nil } func (ec *executionContext) marshalOBodyModification2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐBodyModificationᚄ(ctx context.Context, sel ast.SelectionSet, v []BodyModification) graphql.Marshaler { if v == nil { return graphql.Null } ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNBodyModification2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐBodyModification(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) unmarshalOBodyModificationCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐBodyModificationCriterionInput(ctx context.Context, v any) (*BodyModificationCriterionInput, error) { if v == nil { return nil, nil } res, err := ec.unmarshalInputBodyModificationCriterionInput(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalOBodyModificationInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐBodyModificationInputᚄ(ctx context.Context, v any) ([]BodyModificationInput, error) { if v == nil { return nil, nil } var vSlice []any vSlice = graphql.CoerceList(v) var err error res := make([]BodyModificationInput, len(vSlice)) for i := range vSlice { ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) res[i], err = ec.unmarshalNBodyModificationInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐBodyModificationInput(ctx, vSlice[i]) if err != nil { return nil, err } } return res, nil } func (ec *executionContext) unmarshalOBoolean2bool(ctx context.Context, v any) (bool, error) { res, err := graphql.UnmarshalBoolean(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOBoolean2bool(ctx context.Context, sel ast.SelectionSet, v bool) graphql.Marshaler { _ = sel _ = ctx res := graphql.MarshalBoolean(v) return res } func (ec *executionContext) unmarshalOBoolean2ᚖbool(ctx context.Context, v any) (*bool, error) { if v == nil { return nil, nil } res, err := graphql.UnmarshalBoolean(v) return &res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOBoolean2ᚖbool(ctx context.Context, sel ast.SelectionSet, v *bool) graphql.Marshaler { if v == nil { return graphql.Null } _ = sel _ = ctx res := graphql.MarshalBoolean(*v) return res } func (ec *executionContext) unmarshalOBreastTypeCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐBreastTypeCriterionInput(ctx context.Context, v any) (*BreastTypeCriterionInput, error) { if v == nil { return nil, nil } res, err := ec.unmarshalInputBreastTypeCriterionInput(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalOBreastTypeEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐBreastTypeEnum(ctx context.Context, v any) (*BreastTypeEnum, error) { if v == nil { return nil, nil } var res = new(BreastTypeEnum) err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOBreastTypeEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐBreastTypeEnum(ctx context.Context, sel ast.SelectionSet, v *BreastTypeEnum) graphql.Marshaler { if v == nil { return graphql.Null } return v } func (ec *executionContext) unmarshalODateCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDateCriterionInput(ctx context.Context, v any) (*DateCriterionInput, error) { if v == nil { return nil, nil } res, err := ec.unmarshalInputDateCriterionInput(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalODraft2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDraft(ctx context.Context, sel ast.SelectionSet, v *Draft) graphql.Marshaler { if v == nil { return graphql.Null } return ec._Draft(ctx, sel, v) } func (ec *executionContext) unmarshalODraftEntityInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDraftEntityInputᚄ(ctx context.Context, v any) ([]DraftEntityInput, error) { if v == nil { return nil, nil } var vSlice []any vSlice = graphql.CoerceList(v) var err error res := make([]DraftEntityInput, len(vSlice)) for i := range vSlice { ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) res[i], err = ec.unmarshalNDraftEntityInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDraftEntityInput(ctx, vSlice[i]) if err != nil { return nil, err } } return res, nil } func (ec *executionContext) unmarshalODraftEntityInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐDraftEntityInput(ctx context.Context, v any) (*DraftEntityInput, error) { if v == nil { return nil, nil } res, err := ec.unmarshalInputDraftEntityInput(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOEdit2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEdit(ctx context.Context, sel ast.SelectionSet, v *Edit) graphql.Marshaler { if v == nil { return graphql.Null } return ec._Edit(ctx, sel, v) } func (ec *executionContext) marshalOEditDetails2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditDetails(ctx context.Context, sel ast.SelectionSet, v EditDetails) graphql.Marshaler { if v == nil { return graphql.Null } return ec._EditDetails(ctx, sel, v) } func (ec *executionContext) marshalOEditTarget2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEditTarget(ctx context.Context, sel ast.SelectionSet, v EditTarget) graphql.Marshaler { if v == nil { return graphql.Null } return ec._EditTarget(ctx, sel, v) } func (ec *executionContext) unmarshalOEthnicityEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEthnicityEnum(ctx context.Context, v any) (*EthnicityEnum, error) { if v == nil { return nil, nil } var res = new(EthnicityEnum) err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOEthnicityEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEthnicityEnum(ctx context.Context, sel ast.SelectionSet, v *EthnicityEnum) graphql.Marshaler { if v == nil { return graphql.Null } return v } func (ec *executionContext) unmarshalOEthnicityFilterEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEthnicityFilterEnum(ctx context.Context, v any) (*EthnicityFilterEnum, error) { if v == nil { return nil, nil } var res = new(EthnicityFilterEnum) err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOEthnicityFilterEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEthnicityFilterEnum(ctx context.Context, sel ast.SelectionSet, v *EthnicityFilterEnum) graphql.Marshaler { if v == nil { return graphql.Null } return v } func (ec *executionContext) unmarshalOEyeColorCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEyeColorCriterionInput(ctx context.Context, v any) (*EyeColorCriterionInput, error) { if v == nil { return nil, nil } res, err := ec.unmarshalInputEyeColorCriterionInput(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalOEyeColorEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEyeColorEnum(ctx context.Context, v any) (*EyeColorEnum, error) { if v == nil { return nil, nil } var res = new(EyeColorEnum) err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOEyeColorEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐEyeColorEnum(ctx context.Context, sel ast.SelectionSet, v *EyeColorEnum) graphql.Marshaler { if v == nil { return graphql.Null } return v } func (ec *executionContext) unmarshalOFavoriteFilter2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFavoriteFilter(ctx context.Context, v any) (*FavoriteFilter, error) { if v == nil { return nil, nil } var res = new(FavoriteFilter) err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOFavoriteFilter2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFavoriteFilter(ctx context.Context, sel ast.SelectionSet, v *FavoriteFilter) graphql.Marshaler { if v == nil { return graphql.Null } return v } func (ec *executionContext) marshalOFingerprint2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintᚄ(ctx context.Context, sel ast.SelectionSet, v []Fingerprint) graphql.Marshaler { if v == nil { return graphql.Null } ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNFingerprint2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprint(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) unmarshalOFingerprintEditInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintEditInputᚄ(ctx context.Context, v any) ([]FingerprintEditInput, error) { if v == nil { return nil, nil } var vSlice []any vSlice = graphql.CoerceList(v) var err error res := make([]FingerprintEditInput, len(vSlice)) for i := range vSlice { ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) res[i], err = ec.unmarshalNFingerprintEditInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintEditInput(ctx, vSlice[i]) if err != nil { return nil, err } } return res, nil } func (ec *executionContext) unmarshalOFingerprintInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintInputᚄ(ctx context.Context, v any) ([]FingerprintInput, error) { if v == nil { return nil, nil } var vSlice []any vSlice = graphql.CoerceList(v) var err error res := make([]FingerprintInput, len(vSlice)) for i := range vSlice { ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) res[i], err = ec.unmarshalNFingerprintInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintInput(ctx, vSlice[i]) if err != nil { return nil, err } } return res, nil } func (ec *executionContext) unmarshalOFingerprintSubmissionType2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintSubmissionType(ctx context.Context, v any) (*FingerprintSubmissionType, error) { if v == nil { return nil, nil } var res = new(FingerprintSubmissionType) err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOFingerprintSubmissionType2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFingerprintSubmissionType(ctx context.Context, sel ast.SelectionSet, v *FingerprintSubmissionType) graphql.Marshaler { if v == nil { return graphql.Null } return v } func (ec *executionContext) marshalOFuzzyDate2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐFuzzyDate(ctx context.Context, sel ast.SelectionSet, v *FuzzyDate) graphql.Marshaler { if v == nil { return graphql.Null } return ec._FuzzyDate(ctx, sel, v) } func (ec *executionContext) unmarshalOGenderEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐGenderEnum(ctx context.Context, v any) (*GenderEnum, error) { if v == nil { return nil, nil } var res = new(GenderEnum) err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOGenderEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐGenderEnum(ctx context.Context, sel ast.SelectionSet, v *GenderEnum) graphql.Marshaler { if v == nil { return graphql.Null } return v } func (ec *executionContext) unmarshalOGenderFilterEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐGenderFilterEnum(ctx context.Context, v any) (*GenderFilterEnum, error) { if v == nil { return nil, nil } var res = new(GenderFilterEnum) err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOGenderFilterEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐGenderFilterEnum(ctx context.Context, sel ast.SelectionSet, v *GenderFilterEnum) graphql.Marshaler { if v == nil { return graphql.Null } return v } func (ec *executionContext) unmarshalOGenerateInviteCodeInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐGenerateInviteCodeInput(ctx context.Context, v any) (*GenerateInviteCodeInput, error) { if v == nil { return nil, nil } res, err := ec.unmarshalInputGenerateInviteCodeInput(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalOHairColorCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐHairColorCriterionInput(ctx context.Context, v any) (*HairColorCriterionInput, error) { if v == nil { return nil, nil } res, err := ec.unmarshalInputHairColorCriterionInput(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalOHairColorEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐHairColorEnum(ctx context.Context, v any) (*HairColorEnum, error) { if v == nil { return nil, nil } var res = new(HairColorEnum) err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOHairColorEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐHairColorEnum(ctx context.Context, sel ast.SelectionSet, v *HairColorEnum) graphql.Marshaler { if v == nil { return graphql.Null } return v } func (ec *executionContext) unmarshalOID2ᚕgithubᚗcomᚋgofrsᚋuuidᚐUUIDᚄ(ctx context.Context, v any) ([]uuid.UUID, error) { if v == nil { return nil, nil } var vSlice []any vSlice = graphql.CoerceList(v) var err error res := make([]uuid.UUID, len(vSlice)) for i := range vSlice { ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) res[i], err = ec.unmarshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, vSlice[i]) if err != nil { return nil, err } } return res, nil } func (ec *executionContext) marshalOID2ᚕgithubᚗcomᚋgofrsᚋuuidᚐUUIDᚄ(ctx context.Context, sel ast.SelectionSet, v []uuid.UUID) graphql.Marshaler { if v == nil { return graphql.Null } ret := make(graphql.Array, len(v)) for i := range v { ret[i] = ec.marshalNID2githubᚗcomᚋgofrsᚋuuidᚐUUID(ctx, sel, v[i]) } for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) unmarshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID(ctx context.Context, v any) (*uuid.UUID, error) { if v == nil { return nil, nil } res, err := UnmarshalID(v) return &res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOID2ᚖgithubᚗcomᚋgofrsᚋuuidᚐUUID(ctx context.Context, sel ast.SelectionSet, v *uuid.UUID) graphql.Marshaler { if v == nil { return graphql.Null } _ = sel _ = ctx res := MarshalID(*v) return res } func (ec *executionContext) unmarshalOIDCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐIDCriterionInput(ctx context.Context, v any) (*IDCriterionInput, error) { if v == nil { return nil, nil } res, err := ec.unmarshalInputIDCriterionInput(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOImage2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐImageᚄ(ctx context.Context, sel ast.SelectionSet, v []Image) graphql.Marshaler { if v == nil { return graphql.Null } ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNImage2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐImage(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) marshalOImage2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐImage(ctx context.Context, sel ast.SelectionSet, v *Image) graphql.Marshaler { if v == nil { return graphql.Null } return ec._Image(ctx, sel, v) } func (ec *executionContext) unmarshalOInt2int(ctx context.Context, v any) (int, error) { res, err := graphql.UnmarshalInt(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOInt2int(ctx context.Context, sel ast.SelectionSet, v int) graphql.Marshaler { _ = sel _ = ctx res := graphql.MarshalInt(v) return res } func (ec *executionContext) unmarshalOInt2ᚖint(ctx context.Context, v any) (*int, error) { if v == nil { return nil, nil } res, err := graphql.UnmarshalInt(v) return &res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOInt2ᚖint(ctx context.Context, sel ast.SelectionSet, v *int) graphql.Marshaler { if v == nil { return graphql.Null } _ = sel _ = ctx res := graphql.MarshalInt(*v) return res } func (ec *executionContext) unmarshalOIntCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐIntCriterionInput(ctx context.Context, v any) (*IntCriterionInput, error) { if v == nil { return nil, nil } res, err := ec.unmarshalInputIntCriterionInput(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOInviteKey2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐInviteKeyᚄ(ctx context.Context, sel ast.SelectionSet, v []InviteKey) graphql.Marshaler { if v == nil { return graphql.Null } ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNInviteKey2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐInviteKey(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) unmarshalOMarkNotificationReadInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐMarkNotificationReadInput(ctx context.Context, v any) (*MarkNotificationReadInput, error) { if v == nil { return nil, nil } res, err := ec.unmarshalInputMarkNotificationReadInput(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalOModAuditActionEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐModAuditActionEnum(ctx context.Context, v any) (*ModAuditActionEnum, error) { if v == nil { return nil, nil } var res = new(ModAuditActionEnum) err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOModAuditActionEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐModAuditActionEnum(ctx context.Context, sel ast.SelectionSet, v *ModAuditActionEnum) graphql.Marshaler { if v == nil { return graphql.Null } return v } func (ec *executionContext) unmarshalOMultiIDCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐMultiIDCriterionInput(ctx context.Context, v any) (*MultiIDCriterionInput, error) { if v == nil { return nil, nil } res, err := ec.unmarshalInputMultiIDCriterionInput(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalOMultiStringCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐMultiStringCriterionInput(ctx context.Context, v any) (*MultiStringCriterionInput, error) { if v == nil { return nil, nil } res, err := ec.unmarshalInputMultiStringCriterionInput(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalONotificationEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐNotificationEnum(ctx context.Context, v any) (*NotificationEnum, error) { if v == nil { return nil, nil } var res = new(NotificationEnum) err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalONotificationEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐNotificationEnum(ctx context.Context, sel ast.SelectionSet, v *NotificationEnum) graphql.Marshaler { if v == nil { return graphql.Null } return v } func (ec *executionContext) unmarshalOOperationEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐOperationEnum(ctx context.Context, v any) (*OperationEnum, error) { if v == nil { return nil, nil } var res = new(OperationEnum) err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOOperationEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐOperationEnum(ctx context.Context, sel ast.SelectionSet, v *OperationEnum) graphql.Marshaler { if v == nil { return graphql.Null } return v } func (ec *executionContext) marshalOPerformer2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformer(ctx context.Context, sel ast.SelectionSet, v *Performer) graphql.Marshaler { if v == nil { return graphql.Null } return ec._Performer(ctx, sel, v) } func (ec *executionContext) marshalOPerformerAppearance2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerAppearanceᚄ(ctx context.Context, sel ast.SelectionSet, v []PerformerAppearance) graphql.Marshaler { if v == nil { return graphql.Null } ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNPerformerAppearance2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerAppearance(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) unmarshalOPerformerAppearanceInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerAppearanceInputᚄ(ctx context.Context, v any) ([]PerformerAppearanceInput, error) { if v == nil { return nil, nil } var vSlice []any vSlice = graphql.CoerceList(v) var err error res := make([]PerformerAppearanceInput, len(vSlice)) for i := range vSlice { ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) res[i], err = ec.unmarshalNPerformerAppearanceInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerAppearanceInput(ctx, vSlice[i]) if err != nil { return nil, err } } return res, nil } func (ec *executionContext) unmarshalOPerformerEditDetailsInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerEditDetailsInput(ctx context.Context, v any) (*PerformerEditDetailsInput, error) { if v == nil { return nil, nil } res, err := ec.unmarshalInputPerformerEditDetailsInput(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOPerformerEditOptions2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerEditOptions(ctx context.Context, sel ast.SelectionSet, v *PerformerEditOptions) graphql.Marshaler { if v == nil { return graphql.Null } return ec._PerformerEditOptions(ctx, sel, v) } func (ec *executionContext) unmarshalOPerformerEditOptionsInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerEditOptionsInput(ctx context.Context, v any) (*PerformerEditOptionsInput, error) { if v == nil { return nil, nil } res, err := ec.unmarshalInputPerformerEditOptionsInput(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalOPerformerScenesInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerScenesInput(ctx context.Context, v any) (*PerformerScenesInput, error) { if v == nil { return nil, nil } res, err := ec.unmarshalInputPerformerScenesInput(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOPerformerSearchFacets2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerSearchFacets(ctx context.Context, sel ast.SelectionSet, v *PerformerSearchFacets) graphql.Marshaler { if v == nil { return graphql.Null } return ec._PerformerSearchFacets(ctx, sel, v) } func (ec *executionContext) unmarshalOPerformerSearchFilter2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐPerformerSearchFilter(ctx context.Context, v any) (*PerformerSearchFilter, error) { if v == nil { return nil, nil } res, err := ec.unmarshalInputPerformerSearchFilter(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalORoleCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleCriterionInput(ctx context.Context, v any) (*RoleCriterionInput, error) { if v == nil { return nil, nil } res, err := ec.unmarshalInputRoleCriterionInput(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalORoleEnum2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnumᚄ(ctx context.Context, v any) ([]RoleEnum, error) { if v == nil { return nil, nil } var vSlice []any vSlice = graphql.CoerceList(v) var err error res := make([]RoleEnum, len(vSlice)) for i := range vSlice { ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) res[i], err = ec.unmarshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, vSlice[i]) if err != nil { return nil, err } } return res, nil } func (ec *executionContext) marshalORoleEnum2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnumᚄ(ctx context.Context, sel ast.SelectionSet, v []RoleEnum) graphql.Marshaler { if v == nil { return graphql.Null } ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNRoleEnum2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐRoleEnum(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) marshalOScene2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐScene(ctx context.Context, sel ast.SelectionSet, v *Scene) graphql.Marshaler { if v == nil { return graphql.Null } return ec._Scene(ctx, sel, v) } func (ec *executionContext) marshalOSceneDraftStudio2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneDraftStudio(ctx context.Context, sel ast.SelectionSet, v SceneDraftStudio) graphql.Marshaler { if v == nil { return graphql.Null } return ec._SceneDraftStudio(ctx, sel, v) } func (ec *executionContext) marshalOSceneDraftTag2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneDraftTagᚄ(ctx context.Context, sel ast.SelectionSet, v []SceneDraftTag) graphql.Marshaler { if v == nil { return graphql.Null } ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNSceneDraftTag2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneDraftTag(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) unmarshalOSceneEditDetailsInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSceneEditDetailsInput(ctx context.Context, v any) (*SceneEditDetailsInput, error) { if v == nil { return nil, nil } res, err := ec.unmarshalInputSceneEditDetailsInput(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOSite2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐSite(ctx context.Context, sel ast.SelectionSet, v *Site) graphql.Marshaler { if v == nil { return graphql.Null } return ec._Site(ctx, sel, v) } func (ec *executionContext) unmarshalOString2string(ctx context.Context, v any) (string, error) { res, err := graphql.UnmarshalString(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOString2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { _ = sel _ = ctx res := graphql.MarshalString(v) return res } func (ec *executionContext) unmarshalOString2ᚕstringᚄ(ctx context.Context, v any) ([]string, error) { if v == nil { return nil, nil } var vSlice []any vSlice = graphql.CoerceList(v) var err error res := make([]string, len(vSlice)) for i := range vSlice { ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) res[i], err = ec.unmarshalNString2string(ctx, vSlice[i]) if err != nil { return nil, err } } return res, nil } func (ec *executionContext) marshalOString2ᚕstringᚄ(ctx context.Context, sel ast.SelectionSet, v []string) graphql.Marshaler { if v == nil { return graphql.Null } ret := make(graphql.Array, len(v)) for i := range v { ret[i] = ec.marshalNString2string(ctx, sel, v[i]) } for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) unmarshalOString2ᚖstring(ctx context.Context, v any) (*string, error) { if v == nil { return nil, nil } res, err := graphql.UnmarshalString(v) return &res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOString2ᚖstring(ctx context.Context, sel ast.SelectionSet, v *string) graphql.Marshaler { if v == nil { return graphql.Null } _ = sel _ = ctx res := graphql.MarshalString(*v) return res } func (ec *executionContext) unmarshalOStringCriterionInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStringCriterionInput(ctx context.Context, v any) (*StringCriterionInput, error) { if v == nil { return nil, nil } res, err := ec.unmarshalInputStringCriterionInput(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOStudio2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStudio(ctx context.Context, sel ast.SelectionSet, v *Studio) graphql.Marshaler { if v == nil { return graphql.Null } return ec._Studio(ctx, sel, v) } func (ec *executionContext) unmarshalOStudioEditDetailsInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStudioEditDetailsInput(ctx context.Context, v any) (*StudioEditDetailsInput, error) { if v == nil { return nil, nil } res, err := ec.unmarshalInputStudioEditDetailsInput(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalOStudioQueryInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐStudioQueryInput(ctx context.Context, v any) (*StudioQueryInput, error) { if v == nil { return nil, nil } res, err := ec.unmarshalInputStudioQueryInput(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOTag2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagᚄ(ctx context.Context, sel ast.SelectionSet, v []Tag) graphql.Marshaler { if v == nil { return graphql.Null } ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNTag2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTag(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) marshalOTag2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTag(ctx context.Context, sel ast.SelectionSet, v *Tag) graphql.Marshaler { if v == nil { return graphql.Null } return ec._Tag(ctx, sel, v) } func (ec *executionContext) marshalOTagCategory2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagCategory(ctx context.Context, sel ast.SelectionSet, v *TagCategory) graphql.Marshaler { if v == nil { return graphql.Null } return ec._TagCategory(ctx, sel, v) } func (ec *executionContext) unmarshalOTagEditDetailsInput2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagEditDetailsInput(ctx context.Context, v any) (*TagEditDetailsInput, error) { if v == nil { return nil, nil } res, err := ec.unmarshalInputTagEditDetailsInput(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) unmarshalOTagGroupEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagGroupEnum(ctx context.Context, v any) (*TagGroupEnum, error) { if v == nil { return nil, nil } var res = new(TagGroupEnum) err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOTagGroupEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTagGroupEnum(ctx context.Context, sel ast.SelectionSet, v *TagGroupEnum) graphql.Marshaler { if v == nil { return graphql.Null } return v } func (ec *executionContext) unmarshalOTargetTypeEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTargetTypeEnum(ctx context.Context, v any) (*TargetTypeEnum, error) { if v == nil { return nil, nil } var res = new(TargetTypeEnum) err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOTargetTypeEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐTargetTypeEnum(ctx context.Context, sel ast.SelectionSet, v *TargetTypeEnum) graphql.Marshaler { if v == nil { return graphql.Null } return v } func (ec *executionContext) unmarshalOTime2ᚖtimeᚐTime(ctx context.Context, v any) (*time.Time, error) { if v == nil { return nil, nil } res, err := graphql.UnmarshalTime(v) return &res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOTime2ᚖtimeᚐTime(ctx context.Context, sel ast.SelectionSet, v *time.Time) graphql.Marshaler { if v == nil { return graphql.Null } _ = sel _ = ctx res := graphql.MarshalTime(*v) return res } func (ec *executionContext) marshalOURL2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐURLᚄ(ctx context.Context, sel ast.SelectionSet, v []URL) graphql.Marshaler { if v == nil { return graphql.Null } ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalNURL2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐURL(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) unmarshalOURLInput2ᚕgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐURLᚄ(ctx context.Context, v any) ([]URL, error) { if v == nil { return nil, nil } var vSlice []any vSlice = graphql.CoerceList(v) var err error res := make([]URL, len(vSlice)) for i := range vSlice { ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) res[i], err = ec.unmarshalNURLInput2githubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐURL(ctx, vSlice[i]) if err != nil { return nil, err } } return res, nil } func (ec *executionContext) unmarshalOUpload2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚐUpload(ctx context.Context, v any) (*graphql.Upload, error) { if v == nil { return nil, nil } res, err := graphql.UnmarshalUpload(v) return &res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOUpload2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚐUpload(ctx context.Context, sel ast.SelectionSet, v *graphql.Upload) graphql.Marshaler { if v == nil { return graphql.Null } _ = sel _ = ctx res := graphql.MarshalUpload(*v) return res } func (ec *executionContext) marshalOUser2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUser(ctx context.Context, sel ast.SelectionSet, v *User) graphql.Marshaler { if v == nil { return graphql.Null } return ec._User(ctx, sel, v) } func (ec *executionContext) unmarshalOUserVotedFilterEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUserVotedFilterEnum(ctx context.Context, v any) (*UserVotedFilterEnum, error) { if v == nil { return nil, nil } var res = new(UserVotedFilterEnum) err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOUserVotedFilterEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐUserVotedFilterEnum(ctx context.Context, sel ast.SelectionSet, v *UserVotedFilterEnum) graphql.Marshaler { if v == nil { return graphql.Null } return v } func (ec *executionContext) unmarshalOVoteStatusEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐVoteStatusEnum(ctx context.Context, v any) (*VoteStatusEnum, error) { if v == nil { return nil, nil } var res = new(VoteStatusEnum) err := res.UnmarshalGQL(v) return res, graphql.ErrorOnPath(ctx, err) } func (ec *executionContext) marshalOVoteStatusEnum2ᚖgithubᚗcomᚋstashappᚋstashᚑboxᚋinternalᚋmodelsᚐVoteStatusEnum(ctx context.Context, sel ast.SelectionSet, v *VoteStatusEnum) graphql.Marshaler { if v == nil { return graphql.Null } return v } func (ec *executionContext) marshalO__EnumValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.EnumValue) graphql.Marshaler { if v == nil { return graphql.Null } ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalN__EnumValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValue(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) marshalO__Field2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐFieldᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Field) graphql.Marshaler { if v == nil { return graphql.Null } ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalN__Field2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐField(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) marshalO__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.InputValue) graphql.Marshaler { if v == nil { return graphql.Null } ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalN__InputValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValue(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) marshalO__Schema2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐSchema(ctx context.Context, sel ast.SelectionSet, v *introspection.Schema) graphql.Marshaler { if v == nil { return graphql.Null } return ec.___Schema(ctx, sel, v) } func (ec *executionContext) marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Type) graphql.Marshaler { if v == nil { return graphql.Null } ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler { fc := graphql.GetFieldContext(ctx) fc.Result = &v[i] return ec.marshalN__Type2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, sel, v[i]) }) for _, e := range ret { if e == graphql.Null { return graphql.Null } } return ret } func (ec *executionContext) marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx context.Context, sel ast.SelectionSet, v *introspection.Type) graphql.Marshaler { if v == nil { return graphql.Null } return ec.___Type(ctx, sel, v) } // endregion ***************************** type.gotpl ***************************** ================================================ FILE: internal/models/generated_models.go ================================================ // Code generated by github.com/99designs/gqlgen, DO NOT EDIT. package models import ( "bytes" "fmt" "io" "strconv" "time" "github.com/99designs/gqlgen/graphql" "github.com/gofrs/uuid" ) type DraftData interface { IsDraftData() } type EditDetails interface { IsEditDetails() } type EditTarget interface { IsEditTarget() } type NotificationData interface { IsNotificationData() } type SceneDraftPerformer interface { IsSceneDraftPerformer() } type SceneDraftStudio interface { IsSceneDraftStudio() } type SceneDraftTag interface { IsSceneDraftTag() } type ActivateNewUserInput struct { Name string `json:"name"` ActivationKey uuid.UUID `json:"activation_key"` Password string `json:"password"` } type AmendEditInput struct { ID uuid.UUID `json:"id"` Reason string `json:"reason"` // Fields to remove from the diff (e.g., ["name", "disambiguation"]) RemoveFields []string `json:"remove_fields,omitempty"` // Array items to remove from added arrays RemoveAddedItems []AmendItemRemoval `json:"remove_added_items,omitempty"` // Array items to remove from removed arrays RemoveRemovedItems []AmendItemRemoval `json:"remove_removed_items,omitempty"` } type AmendItemRemoval struct { // Field name (e.g., "aliases", "urls", "images") Field string `json:"field"` // Indices to remove from the array Indices []int `json:"indices"` } type ApplyEditInput struct { ID uuid.UUID `json:"id"` } type BodyModification struct { Location string `json:"location"` Description *string `json:"description,omitempty"` } type BodyModificationCriterionInput struct { Location *string `json:"location,omitempty"` Description *string `json:"description,omitempty"` Modifier CriterionModifier `json:"modifier"` } type BodyModificationInput struct { Location string `json:"location"` Description *string `json:"description,omitempty"` } type BreastTypeCriterionInput struct { Value *BreastTypeEnum `json:"value,omitempty"` Modifier CriterionModifier `json:"modifier"` } type CancelEditInput struct { ID uuid.UUID `json:"id"` } type CommentCommentedEdit struct { Comment *EditComment `json:"comment"` } func (CommentCommentedEdit) IsNotificationData() {} type CommentOwnEdit struct { Comment *EditComment `json:"comment"` } func (CommentOwnEdit) IsNotificationData() {} type CommentVotedEdit struct { Comment *EditComment `json:"comment"` } func (CommentVotedEdit) IsNotificationData() {} type DateCriterionInput struct { Value string `json:"value"` Modifier CriterionModifier `json:"modifier"` } type DeleteEditInput struct { ID uuid.UUID `json:"id"` Reason string `json:"reason"` } type DeleteFingerprintSubmissionsInput struct { Fingerprints []FingerprintQueryInput `json:"fingerprints"` SceneID uuid.UUID `json:"scene_id"` } type DownvoteOwnEdit struct { Edit *Edit `json:"edit"` } func (DownvoteOwnEdit) IsNotificationData() {} type DraftEntityInput struct { Name string `json:"name"` ID *uuid.UUID `json:"id,omitempty"` } type DraftFingerprint struct { Hash FingerprintHash `json:"hash"` Algorithm FingerprintAlgorithm `json:"algorithm"` Duration int `json:"duration"` } type DraftSubmissionStatus struct { ID *uuid.UUID `json:"id,omitempty"` } type EditCommentInput struct { ID uuid.UUID `json:"id"` Comment string `json:"comment"` } type EditInput struct { // Not required for create type ID *uuid.UUID `json:"id,omitempty"` Operation OperationEnum `json:"operation"` // Only required for merge type MergeSourceIds []uuid.UUID `json:"merge_source_ids,omitempty"` Comment *string `json:"comment,omitempty"` // Edit submitted by an automated script. Requires bot permission Bot *bool `json:"bot,omitempty"` } type EditQueryInput struct { // Filter by user id UserID *uuid.UUID `json:"user_id,omitempty"` // Filter by status Status *VoteStatusEnum `json:"status,omitempty"` // Filter by operation Operation *OperationEnum `json:"operation,omitempty"` // Filter by vote count VoteCount *IntCriterionInput `json:"vote_count,omitempty"` // Filter by applied status Applied *bool `json:"applied,omitempty"` // Filter by target type TargetType *TargetTypeEnum `json:"target_type,omitempty"` // Filter by target id TargetID *uuid.UUID `json:"target_id,omitempty"` // Filter by favorite status IsFavorite *bool `json:"is_favorite,omitempty"` // Filter by user voted status Voted *UserVotedFilterEnum `json:"voted,omitempty"` // Filter to bot edits only IsBot *bool `json:"is_bot,omitempty"` // Filter out user's own edits IncludeUserSubmitted *bool `json:"include_user_submitted,omitempty"` Page int `json:"page"` PerPage int `json:"per_page"` Direction SortDirectionEnum `json:"direction"` Sort EditSortEnum `json:"sort"` } type EditVoteInput struct { ID uuid.UUID `json:"id"` Vote VoteTypeEnum `json:"vote"` } type EyeColorCriterionInput struct { Value *EyeColorEnum `json:"value,omitempty"` Modifier CriterionModifier `json:"modifier"` } type FailedOwnEdit struct { Edit *Edit `json:"edit"` } func (FailedOwnEdit) IsNotificationData() {} type FavoritePerformerEdit struct { Edit *Edit `json:"edit"` } func (FavoritePerformerEdit) IsNotificationData() {} type FavoritePerformerScene struct { Scene *Scene `json:"scene"` } func (FavoritePerformerScene) IsNotificationData() {} type FavoriteStudioEdit struct { Edit *Edit `json:"edit"` } func (FavoriteStudioEdit) IsNotificationData() {} type FavoriteStudioScene struct { Scene *Scene `json:"scene"` } func (FavoriteStudioScene) IsNotificationData() {} type Fingerprint struct { Hash FingerprintHash `json:"hash"` Algorithm FingerprintAlgorithm `json:"algorithm"` Duration int `json:"duration"` // number of times this fingerprint has been submitted (excluding reports) Submissions int `json:"submissions"` // number of times this fingerprint has been reported Reports int `json:"reports"` Created time.Time `json:"created"` Updated time.Time `json:"updated"` // true if the current user submitted this fingerprint UserSubmitted bool `json:"user_submitted"` // true if the current user reported this fingerprint UserReported bool `json:"user_reported"` } type FingerprintBatchSubmission struct { SceneID uuid.UUID `json:"scene_id"` Hash FingerprintHash `json:"hash"` Algorithm FingerprintAlgorithm `json:"algorithm"` Duration int `json:"duration"` } type FingerprintEditInput struct { UserIds []uuid.UUID `json:"user_ids,omitempty"` Hash FingerprintHash `json:"hash"` Algorithm FingerprintAlgorithm `json:"algorithm"` Duration int `json:"duration"` Created time.Time `json:"created"` Submissions *int `json:"submissions,omitempty"` Updated *time.Time `json:"updated,omitempty"` } type FingerprintInput struct { // assumes current user if omitted. Ignored for non-modify Users UserIds []uuid.UUID `json:"user_ids,omitempty"` Hash FingerprintHash `json:"hash"` Algorithm FingerprintAlgorithm `json:"algorithm"` Duration int `json:"duration"` } type FingerprintQueryInput struct { Hash FingerprintHash `json:"hash"` Algorithm FingerprintAlgorithm `json:"algorithm"` } type FingerprintSubmission struct { SceneID uuid.UUID `json:"scene_id"` Fingerprint *FingerprintInput `json:"fingerprint"` Unmatch *bool `json:"unmatch,omitempty"` Vote *FingerprintSubmissionType `json:"vote,omitempty"` } type FingerprintSubmissionResult struct { // The fingerprint hash that was submitted Hash FingerprintHash `json:"hash"` // The scene ID that was submitted to SceneID uuid.UUID `json:"scene_id"` // Error message if submission failed Error *string `json:"error,omitempty"` } type FingerprintedSceneEdit struct { Edit *Edit `json:"edit"` } func (FingerprintedSceneEdit) IsNotificationData() {} type FuzzyDate struct { Date string `json:"date"` Accuracy DateAccuracyEnum `json:"accuracy"` } type GenerateInviteCodeInput struct { Keys *int `json:"keys,omitempty"` Uses *int `json:"uses,omitempty"` TTL *int `json:"ttl,omitempty"` } type GrantInviteInput struct { UserID uuid.UUID `json:"user_id"` Amount int `json:"amount"` } type HairColorCriterionInput struct { Value *HairColorEnum `json:"value,omitempty"` Modifier CriterionModifier `json:"modifier"` } type IDCriterionInput struct { Value []uuid.UUID `json:"value"` Modifier CriterionModifier `json:"modifier"` } type ImageCreateInput struct { URL *string `json:"url,omitempty"` File *graphql.Upload `json:"file,omitempty"` } type ImageDestroyInput struct { ID uuid.UUID `json:"id"` } type ImageUpdateInput struct { ID uuid.UUID `json:"id"` URL *string `json:"url,omitempty"` } type IntCriterionInput struct { Value int `json:"value"` Modifier CriterionModifier `json:"modifier"` } type MarkNotificationReadInput struct { Type NotificationEnum `json:"type"` ID uuid.UUID `json:"id"` } type Measurements struct { CupSize *string `json:"cup_size,omitempty"` BandSize *int `json:"band_size,omitempty"` Waist *int `json:"waist,omitempty"` Hip *int `json:"hip,omitempty"` } type ModAuditQueryInput struct { Page int `json:"page"` PerPage int `json:"per_page"` Action *ModAuditActionEnum `json:"action,omitempty"` UserID *uuid.UUID `json:"user_id,omitempty"` } type MoveFingerprintSubmissionsInput struct { Fingerprints []FingerprintQueryInput `json:"fingerprints"` SourceSceneID uuid.UUID `json:"source_scene_id"` TargetSceneID uuid.UUID `json:"target_scene_id"` } type MultiIDCriterionInput struct { Value []uuid.UUID `json:"value,omitempty"` Modifier CriterionModifier `json:"modifier"` } type MultiStringCriterionInput struct { Value []string `json:"value"` Modifier CriterionModifier `json:"modifier"` } type Mutation struct { } type NewUserInput struct { Email string `json:"email"` InviteKey *uuid.UUID `json:"invite_key,omitempty"` } type PerformerAppearance struct { Performer *Performer `json:"performer"` // Performing as alias As *string `json:"as,omitempty"` } type PerformerAppearanceInput struct { PerformerID uuid.UUID `json:"performer_id"` // Performing as alias As *string `json:"as,omitempty"` } type PerformerCreateInput struct { Name string `json:"name"` Disambiguation *string `json:"disambiguation,omitempty"` Aliases []string `json:"aliases,omitempty"` Gender *GenderEnum `json:"gender,omitempty"` Urls []URL `json:"urls,omitempty"` Birthdate *string `json:"birthdate,omitempty"` Deathdate *string `json:"deathdate,omitempty"` Ethnicity *EthnicityEnum `json:"ethnicity,omitempty"` Country *string `json:"country,omitempty"` EyeColor *EyeColorEnum `json:"eye_color,omitempty"` HairColor *HairColorEnum `json:"hair_color,omitempty"` Height *int `json:"height,omitempty"` CupSize *string `json:"cup_size,omitempty"` BandSize *int `json:"band_size,omitempty"` WaistSize *int `json:"waist_size,omitempty"` HipSize *int `json:"hip_size,omitempty"` BreastType *BreastTypeEnum `json:"breast_type,omitempty"` CareerStartYear *int `json:"career_start_year,omitempty"` CareerEndYear *int `json:"career_end_year,omitempty"` Tattoos []BodyModificationInput `json:"tattoos,omitempty"` Piercings []BodyModificationInput `json:"piercings,omitempty"` ImageIds []uuid.UUID `json:"image_ids,omitempty"` DraftID *uuid.UUID `json:"draft_id,omitempty"` } type PerformerDestroyInput struct { ID uuid.UUID `json:"id"` } type PerformerDraftInput struct { ID *uuid.UUID `json:"id,omitempty"` Disambiguation *string `json:"disambiguation,omitempty"` Name string `json:"name"` Aliases *string `json:"aliases,omitempty"` Gender *string `json:"gender,omitempty"` Birthdate *string `json:"birthdate,omitempty"` Deathdate *string `json:"deathdate,omitempty"` Urls []string `json:"urls,omitempty"` Ethnicity *string `json:"ethnicity,omitempty"` Country *string `json:"country,omitempty"` EyeColor *string `json:"eye_color,omitempty"` HairColor *string `json:"hair_color,omitempty"` Height *string `json:"height,omitempty"` Measurements *string `json:"measurements,omitempty"` BreastType *string `json:"breast_type,omitempty"` Tattoos *string `json:"tattoos,omitempty"` Piercings *string `json:"piercings,omitempty"` CareerStartYear *int `json:"career_start_year,omitempty"` CareerEndYear *int `json:"career_end_year,omitempty"` Image *graphql.Upload `json:"image,omitempty"` } type PerformerEditDetailsInput struct { Name *string `json:"name,omitempty"` Disambiguation *string `json:"disambiguation,omitempty"` Aliases []string `json:"aliases,omitempty"` Gender *GenderEnum `json:"gender,omitempty"` Urls []URL `json:"urls,omitempty"` Birthdate *string `json:"birthdate,omitempty"` Deathdate *string `json:"deathdate,omitempty"` Ethnicity *EthnicityEnum `json:"ethnicity,omitempty"` Country *string `json:"country,omitempty"` EyeColor *EyeColorEnum `json:"eye_color,omitempty"` HairColor *HairColorEnum `json:"hair_color,omitempty"` Height *int `json:"height,omitempty"` CupSize *string `json:"cup_size,omitempty"` BandSize *int `json:"band_size,omitempty"` WaistSize *int `json:"waist_size,omitempty"` HipSize *int `json:"hip_size,omitempty"` BreastType *BreastTypeEnum `json:"breast_type,omitempty"` CareerStartYear *int `json:"career_start_year,omitempty"` CareerEndYear *int `json:"career_end_year,omitempty"` Tattoos []BodyModificationInput `json:"tattoos,omitempty"` Piercings []BodyModificationInput `json:"piercings,omitempty"` ImageIds []uuid.UUID `json:"image_ids,omitempty"` DraftID *uuid.UUID `json:"draft_id,omitempty"` } type PerformerEditInput struct { Edit *EditInput `json:"edit"` // Not required for destroy type Details *PerformerEditDetailsInput `json:"details,omitempty"` // Controls aliases modification for merges and name modifications Options *PerformerEditOptionsInput `json:"options,omitempty"` } type PerformerEditOptions struct { // Set performer alias on scenes without alias to old name if name is changed SetModifyAliases bool `json:"set_modify_aliases"` // Set performer alias on scenes attached to merge sources to old name SetMergeAliases bool `json:"set_merge_aliases"` } type PerformerEditOptionsInput struct { // Set performer alias on scenes without alias to old name if name is changed SetModifyAliases *bool `json:"set_modify_aliases,omitempty"` // Set performer alias on scenes attached to merge sources to old name SetMergeAliases *bool `json:"set_merge_aliases,omitempty"` } type PerformerQueryInput struct { // Searches name and disambiguation - assumes like query unless quoted Names *string `json:"names,omitempty"` // Searches name only - assumes like query unless quoted Name *string `json:"name,omitempty"` // Search aliases only - assumes like query unless quoted Alias *string `json:"alias,omitempty"` Disambiguation *StringCriterionInput `json:"disambiguation,omitempty"` Gender *GenderFilterEnum `json:"gender,omitempty"` // Filter to search urls - assumes like query unless quoted URL *string `json:"url,omitempty"` Birthdate *DateCriterionInput `json:"birthdate,omitempty"` Deathdate *DateCriterionInput `json:"deathdate,omitempty"` BirthYear *IntCriterionInput `json:"birth_year,omitempty"` Age *IntCriterionInput `json:"age,omitempty"` Ethnicity *EthnicityFilterEnum `json:"ethnicity,omitempty"` Country *StringCriterionInput `json:"country,omitempty"` EyeColor *EyeColorCriterionInput `json:"eye_color,omitempty"` HairColor *HairColorCriterionInput `json:"hair_color,omitempty"` Height *IntCriterionInput `json:"height,omitempty"` CupSize *StringCriterionInput `json:"cup_size,omitempty"` BandSize *IntCriterionInput `json:"band_size,omitempty"` WaistSize *IntCriterionInput `json:"waist_size,omitempty"` HipSize *IntCriterionInput `json:"hip_size,omitempty"` BreastType *BreastTypeCriterionInput `json:"breast_type,omitempty"` CareerStartYear *IntCriterionInput `json:"career_start_year,omitempty"` CareerEndYear *IntCriterionInput `json:"career_end_year,omitempty"` Tattoos *BodyModificationCriterionInput `json:"tattoos,omitempty"` Piercings *BodyModificationCriterionInput `json:"piercings,omitempty"` // Filter by performerfavorite status for the current user IsFavorite *bool `json:"is_favorite,omitempty"` // Filter by a performer they have performed in scenes with PerformedWith *uuid.UUID `json:"performed_with,omitempty"` // Filter by a studio StudioID *uuid.UUID `json:"studio_id,omitempty"` Page int `json:"page"` PerPage int `json:"per_page"` Direction SortDirectionEnum `json:"direction"` Sort PerformerSortEnum `json:"sort"` } type PerformerScenesInput struct { // Filter by another performer that also performs in the scenes PerformedWith *uuid.UUID `json:"performed_with,omitempty"` // Filter by a studio StudioID *uuid.UUID `json:"studio_id,omitempty"` // Filter by tags Tags *MultiIDCriterionInput `json:"tags,omitempty"` } type PerformerSearchFilter struct { // Filter by gender Gender *GenderEnum `json:"gender,omitempty"` } type PerformerStudio struct { Studio *Studio `json:"studio"` SceneCount int `json:"scene_count"` } type PerformerUpdateInput struct { ID uuid.UUID `json:"id"` Name *string `json:"name,omitempty"` Disambiguation *string `json:"disambiguation,omitempty"` Aliases []string `json:"aliases,omitempty"` Gender *GenderEnum `json:"gender,omitempty"` Urls []URL `json:"urls,omitempty"` Birthdate *string `json:"birthdate,omitempty"` Deathdate *string `json:"deathdate,omitempty"` Ethnicity *EthnicityEnum `json:"ethnicity,omitempty"` Country *string `json:"country,omitempty"` EyeColor *EyeColorEnum `json:"eye_color,omitempty"` HairColor *HairColorEnum `json:"hair_color,omitempty"` Height *int `json:"height,omitempty"` CupSize *string `json:"cup_size,omitempty"` BandSize *int `json:"band_size,omitempty"` WaistSize *int `json:"waist_size,omitempty"` HipSize *int `json:"hip_size,omitempty"` BreastType *BreastTypeEnum `json:"breast_type,omitempty"` CareerStartYear *int `json:"career_start_year,omitempty"` CareerEndYear *int `json:"career_end_year,omitempty"` Tattoos []BodyModificationInput `json:"tattoos,omitempty"` Piercings []BodyModificationInput `json:"piercings,omitempty"` ImageIds []uuid.UUID `json:"image_ids,omitempty"` } // The query root for this schema type Query struct { } type QueryExistingPerformerInput struct { Name *string `json:"name,omitempty"` Disambiguation *string `json:"disambiguation,omitempty"` Urls []string `json:"urls"` } type QueryExistingSceneInput struct { Title *string `json:"title,omitempty"` StudioID *uuid.UUID `json:"studio_id,omitempty"` Fingerprints []FingerprintInput `json:"fingerprints"` } type QueryNotificationsInput struct { Page int `json:"page"` PerPage int `json:"per_page"` Type *NotificationEnum `json:"type,omitempty"` UnreadOnly *bool `json:"unread_only,omitempty"` } type QuerySitesResultType struct { Count int `json:"count"` Sites []Site `json:"sites"` } type QueryStudiosResultType struct { Count int `json:"count"` Studios []Studio `json:"studios"` } type QueryTagCategoriesResultType struct { Count int `json:"count"` TagCategories []TagCategory `json:"tag_categories"` } type QueryTagsResultType struct { Count int `json:"count"` Tags []Tag `json:"tags"` } type QueryUsersResultType struct { Count int `json:"count"` Users []User `json:"users"` } type ResetPasswordInput struct { Email string `json:"email"` } type RevokeInviteInput struct { UserID uuid.UUID `json:"user_id"` Amount int `json:"amount"` } type RoleCriterionInput struct { Value []RoleEnum `json:"value"` Modifier CriterionModifier `json:"modifier"` } type SceneCreateInput struct { Title *string `json:"title,omitempty"` Details *string `json:"details,omitempty"` Urls []URL `json:"urls,omitempty"` Date string `json:"date"` ProductionDate *string `json:"production_date,omitempty"` StudioID *uuid.UUID `json:"studio_id,omitempty"` Performers []PerformerAppearanceInput `json:"performers,omitempty"` TagIds []uuid.UUID `json:"tag_ids,omitempty"` ImageIds []uuid.UUID `json:"image_ids,omitempty"` Fingerprints []FingerprintEditInput `json:"fingerprints"` Duration *int `json:"duration,omitempty"` Director *string `json:"director,omitempty"` Code *string `json:"code,omitempty"` } type SceneDestroyInput struct { ID uuid.UUID `json:"id"` } type SceneDraftInput struct { ID *uuid.UUID `json:"id,omitempty"` Title *string `json:"title,omitempty"` Code *string `json:"code,omitempty"` Details *string `json:"details,omitempty"` Director *string `json:"director,omitempty"` URL *string `json:"url,omitempty"` Urls []string `json:"urls,omitempty"` Date *string `json:"date,omitempty"` ProductionDate *string `json:"production_date,omitempty"` Studio *DraftEntityInput `json:"studio,omitempty"` Performers []DraftEntityInput `json:"performers"` Tags []DraftEntityInput `json:"tags,omitempty"` Image *graphql.Upload `json:"image,omitempty"` Fingerprints []FingerprintInput `json:"fingerprints"` } type SceneEditDetailsInput struct { Title *string `json:"title,omitempty"` Details *string `json:"details,omitempty"` Urls []URL `json:"urls,omitempty"` Date *string `json:"date,omitempty"` ProductionDate *string `json:"production_date,omitempty"` StudioID *uuid.UUID `json:"studio_id,omitempty"` Performers []PerformerAppearanceInput `json:"performers,omitempty"` TagIds []uuid.UUID `json:"tag_ids,omitempty"` ImageIds []uuid.UUID `json:"image_ids,omitempty"` Duration *int `json:"duration,omitempty"` Director *string `json:"director,omitempty"` Code *string `json:"code,omitempty"` Fingerprints []FingerprintInput `json:"fingerprints,omitempty"` DraftID *uuid.UUID `json:"draft_id,omitempty"` } type SceneEditInput struct { Edit *EditInput `json:"edit"` // Not required for destroy type Details *SceneEditDetailsInput `json:"details,omitempty"` } type SceneQueryInput struct { // Filter to search title and details - assumes like query unless quoted Text *string `json:"text,omitempty"` // Filter to search title - assumes like query unless quoted Title *string `json:"title,omitempty"` // Filter to search urls - assumes like query unless quoted URL *string `json:"url,omitempty"` // Filter by date Date *DateCriterionInput `json:"date,omitempty"` // Filter by production date ProductionDate *DateCriterionInput `json:"production_date,omitempty"` // Filter to only include scenes with this studio Studios *MultiIDCriterionInput `json:"studios,omitempty"` // Filter to only include scenes with this studio as primary or parent ParentStudio *string `json:"parentStudio,omitempty"` // Filter to only include scenes with these tags Tags *MultiIDCriterionInput `json:"tags,omitempty"` // Filter to only include scenes with these performers Performers *MultiIDCriterionInput `json:"performers,omitempty"` // Filter to include scenes with performer appearing as alias Alias *StringCriterionInput `json:"alias,omitempty"` // Filter to only include scenes with these fingerprints Fingerprints *MultiStringCriterionInput `json:"fingerprints,omitempty"` // Filter by favorited entity Favorites *FavoriteFilter `json:"favorites,omitempty"` // Filter to scenes with fingerprints submitted by the user HasFingerprintSubmissions *bool `json:"has_fingerprint_submissions,omitempty"` Page int `json:"page"` PerPage int `json:"per_page"` Direction SortDirectionEnum `json:"direction"` Sort SceneSortEnum `json:"sort"` } type SceneUpdateInput struct { ID uuid.UUID `json:"id"` Title *string `json:"title,omitempty"` Details *string `json:"details,omitempty"` Urls []URL `json:"urls,omitempty"` Date *string `json:"date,omitempty"` ProductionDate *string `json:"production_date,omitempty"` StudioID *uuid.UUID `json:"studio_id,omitempty"` Performers []PerformerAppearanceInput `json:"performers,omitempty"` TagIds []uuid.UUID `json:"tag_ids,omitempty"` ImageIds []uuid.UUID `json:"image_ids,omitempty"` Fingerprints []FingerprintEditInput `json:"fingerprints,omitempty"` Duration *int `json:"duration,omitempty"` Director *string `json:"director,omitempty"` Code *string `json:"code,omitempty"` } type SiteCreateInput struct { Name string `json:"name"` Description *string `json:"description,omitempty"` URL *string `json:"url,omitempty"` Regex *string `json:"regex,omitempty"` ValidTypes []ValidSiteTypeEnum `json:"valid_types"` } type SiteDestroyInput struct { ID uuid.UUID `json:"id"` } type SiteUpdateInput struct { ID uuid.UUID `json:"id"` Name string `json:"name"` Description *string `json:"description,omitempty"` URL *string `json:"url,omitempty"` Regex *string `json:"regex,omitempty"` ValidTypes []ValidSiteTypeEnum `json:"valid_types"` } type StashBoxConfig struct { HostURL string `json:"host_url"` RequireInvite bool `json:"require_invite"` RequireActivation bool `json:"require_activation"` VotePromotionThreshold *int `json:"vote_promotion_threshold,omitempty"` VoteApplicationThreshold int `json:"vote_application_threshold"` VotingPeriod int `json:"voting_period"` MinDestructiveVotingPeriod int `json:"min_destructive_voting_period"` VoteCronInterval string `json:"vote_cron_interval"` GuidelinesURL string `json:"guidelines_url"` RequireSceneDraft bool `json:"require_scene_draft"` EditUpdateLimit int `json:"edit_update_limit"` RequireTagRole bool `json:"require_tag_role"` } type StringCriterionInput struct { Value string `json:"value"` Modifier CriterionModifier `json:"modifier"` } type StudioCreateInput struct { Name string `json:"name"` Aliases []string `json:"aliases,omitempty"` Urls []URL `json:"urls,omitempty"` ParentID *uuid.UUID `json:"parent_id,omitempty"` ImageIds []uuid.UUID `json:"image_ids,omitempty"` } type StudioDestroyInput struct { ID uuid.UUID `json:"id"` } type StudioEditDetailsInput struct { Name *string `json:"name,omitempty"` Aliases []string `json:"aliases,omitempty"` Urls []URL `json:"urls,omitempty"` ParentID *uuid.UUID `json:"parent_id,omitempty"` ImageIds []uuid.UUID `json:"image_ids,omitempty"` } type StudioEditInput struct { Edit *EditInput `json:"edit"` // Not required for destroy type Details *StudioEditDetailsInput `json:"details,omitempty"` } type StudioQueryInput struct { // Filter to search name - assumes like query unless quoted Name *string `json:"name,omitempty"` // Filter to search studio name, aliases and parent studio name - assumes like query unless quoted Names *string `json:"names,omitempty"` // Filter to search url - assumes like query unless quoted URL *string `json:"url,omitempty"` Parent *IDCriterionInput `json:"parent,omitempty"` HasParent *bool `json:"has_parent,omitempty"` // Filter by studio favorite status for the current user IsFavorite *bool `json:"is_favorite,omitempty"` Page int `json:"page"` PerPage int `json:"per_page"` Direction SortDirectionEnum `json:"direction"` Sort StudioSortEnum `json:"sort"` } type StudioUpdateInput struct { ID uuid.UUID `json:"id"` Name *string `json:"name,omitempty"` Aliases []string `json:"aliases,omitempty"` Urls []URL `json:"urls,omitempty"` ParentID *uuid.UUID `json:"parent_id,omitempty"` ImageIds []uuid.UUID `json:"image_ids,omitempty"` } type TagCategoryCreateInput struct { Name string `json:"name"` Group TagGroupEnum `json:"group"` Description *string `json:"description,omitempty"` } type TagCategoryDestroyInput struct { ID uuid.UUID `json:"id"` } type TagCategoryUpdateInput struct { ID uuid.UUID `json:"id"` Name *string `json:"name,omitempty"` Group *TagGroupEnum `json:"group,omitempty"` Description *string `json:"description,omitempty"` } type TagCreateInput struct { Name string `json:"name"` Description *string `json:"description,omitempty"` Aliases []string `json:"aliases,omitempty"` CategoryID *uuid.UUID `json:"category_id,omitempty"` } type TagDestroyInput struct { ID uuid.UUID `json:"id"` } type TagEditDetailsInput struct { Name *string `json:"name,omitempty"` Description *string `json:"description,omitempty"` Aliases []string `json:"aliases,omitempty"` CategoryID *uuid.UUID `json:"category_id,omitempty"` } type TagEditInput struct { Edit *EditInput `json:"edit"` // Not required for destroy type Details *TagEditDetailsInput `json:"details,omitempty"` } type TagQueryInput struct { // Filter to search name, aliases and description - assumes like query unless quoted Text *string `json:"text,omitempty"` // Searches name and aliases - assumes like query unless quoted Names *string `json:"names,omitempty"` // Filter to search name - assumes like query unless quoted Name *string `json:"name,omitempty"` // Filter to category ID CategoryID *uuid.UUID `json:"category_id,omitempty"` Page int `json:"page"` PerPage int `json:"per_page"` Direction SortDirectionEnum `json:"direction"` Sort TagSortEnum `json:"sort"` } type TagUpdateInput struct { ID uuid.UUID `json:"id"` Name *string `json:"name,omitempty"` Description *string `json:"description,omitempty"` Aliases []string `json:"aliases,omitempty"` CategoryID *uuid.UUID `json:"category_id,omitempty"` } type UpdatedEdit struct { Edit *Edit `json:"edit"` } func (UpdatedEdit) IsNotificationData() {} type UserChangeEmailInput struct { ExistingEmailToken *uuid.UUID `json:"existing_email_token,omitempty"` NewEmailToken *uuid.UUID `json:"new_email_token,omitempty"` NewEmail *string `json:"new_email,omitempty"` } type UserChangePasswordInput struct { // Password in plain text ExistingPassword *string `json:"existing_password,omitempty"` NewPassword string `json:"new_password"` ResetKey *uuid.UUID `json:"reset_key,omitempty"` } type UserCreateInput struct { Name string `json:"name"` // Password in plain text Password string `json:"password"` Roles []RoleEnum `json:"roles"` Email string `json:"email"` InvitedByID *uuid.UUID `json:"invited_by_id,omitempty"` } type UserDestroyInput struct { ID uuid.UUID `json:"id"` } type UserEditCount struct { Accepted int `json:"accepted"` Rejected int `json:"rejected"` Pending int `json:"pending"` ImmediateAccepted int `json:"immediate_accepted"` ImmediateRejected int `json:"immediate_rejected"` Failed int `json:"failed"` Canceled int `json:"canceled"` } type UserQueryInput struct { // Filter to search user name - assumes like query unless quoted Name *string `json:"name,omitempty"` // Filter to search email - assumes like query unless quoted Email *string `json:"email,omitempty"` // Filter by roles Roles *RoleCriterionInput `json:"roles,omitempty"` // Filter by api key APIKey *string `json:"apiKey,omitempty"` // Filter by successful edits SuccessfulEdits *IntCriterionInput `json:"successful_edits,omitempty"` // Filter by unsuccessful edits UnsuccessfulEdits *IntCriterionInput `json:"unsuccessful_edits,omitempty"` // Filter by votes on successful edits SuccessfulVotes *IntCriterionInput `json:"successful_votes,omitempty"` // Filter by votes on unsuccessful edits UnsuccessfulVotes *IntCriterionInput `json:"unsuccessful_votes,omitempty"` // Filter by number of API calls APICalls *IntCriterionInput `json:"api_calls,omitempty"` // Filter by user that invited InvitedBy *uuid.UUID `json:"invited_by,omitempty"` Page int `json:"page"` PerPage int `json:"per_page"` } type UserUpdateInput struct { ID uuid.UUID `json:"id"` Name *string `json:"name,omitempty"` // Password in plain text Password *string `json:"password,omitempty"` Roles []RoleEnum `json:"roles,omitempty"` Email *string `json:"email,omitempty"` } type UserVoteCount struct { Abstain int `json:"abstain"` Accept int `json:"accept"` Reject int `json:"reject"` ImmediateAccept int `json:"immediate_accept"` ImmediateReject int `json:"immediate_reject"` } type Version struct { Hash string `json:"hash"` BuildTime string `json:"build_time"` BuildType string `json:"build_type"` Version string `json:"version"` } type BreastTypeEnum string const ( BreastTypeEnumNatural BreastTypeEnum = "NATURAL" BreastTypeEnumFake BreastTypeEnum = "FAKE" BreastTypeEnumNa BreastTypeEnum = "NA" ) var AllBreastTypeEnum = []BreastTypeEnum{ BreastTypeEnumNatural, BreastTypeEnumFake, BreastTypeEnumNa, } func (e BreastTypeEnum) IsValid() bool { switch e { case BreastTypeEnumNatural, BreastTypeEnumFake, BreastTypeEnumNa: return true } return false } func (e BreastTypeEnum) String() string { return string(e) } func (e *BreastTypeEnum) UnmarshalGQL(v any) error { str, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } *e = BreastTypeEnum(str) if !e.IsValid() { return fmt.Errorf("%s is not a valid BreastTypeEnum", str) } return nil } func (e BreastTypeEnum) MarshalGQL(w io.Writer) { fmt.Fprint(w, strconv.Quote(e.String())) } func (e *BreastTypeEnum) UnmarshalJSON(b []byte) error { s, err := strconv.Unquote(string(b)) if err != nil { return err } return e.UnmarshalGQL(s) } func (e BreastTypeEnum) MarshalJSON() ([]byte, error) { var buf bytes.Buffer e.MarshalGQL(&buf) return buf.Bytes(), nil } type CriterionModifier string const ( // = CriterionModifierEquals CriterionModifier = "EQUALS" // != CriterionModifierNotEquals CriterionModifier = "NOT_EQUALS" // > CriterionModifierGreaterThan CriterionModifier = "GREATER_THAN" // < CriterionModifierLessThan CriterionModifier = "LESS_THAN" // IS NULL CriterionModifierIsNull CriterionModifier = "IS_NULL" // IS NOT NULL CriterionModifierNotNull CriterionModifier = "NOT_NULL" // INCLUDES ALL CriterionModifierIncludesAll CriterionModifier = "INCLUDES_ALL" CriterionModifierIncludes CriterionModifier = "INCLUDES" CriterionModifierExcludes CriterionModifier = "EXCLUDES" ) var AllCriterionModifier = []CriterionModifier{ CriterionModifierEquals, CriterionModifierNotEquals, CriterionModifierGreaterThan, CriterionModifierLessThan, CriterionModifierIsNull, CriterionModifierNotNull, CriterionModifierIncludesAll, CriterionModifierIncludes, CriterionModifierExcludes, } func (e CriterionModifier) IsValid() bool { switch e { case CriterionModifierEquals, CriterionModifierNotEquals, CriterionModifierGreaterThan, CriterionModifierLessThan, CriterionModifierIsNull, CriterionModifierNotNull, CriterionModifierIncludesAll, CriterionModifierIncludes, CriterionModifierExcludes: return true } return false } func (e CriterionModifier) String() string { return string(e) } func (e *CriterionModifier) UnmarshalGQL(v any) error { str, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } *e = CriterionModifier(str) if !e.IsValid() { return fmt.Errorf("%s is not a valid CriterionModifier", str) } return nil } func (e CriterionModifier) MarshalGQL(w io.Writer) { fmt.Fprint(w, strconv.Quote(e.String())) } func (e *CriterionModifier) UnmarshalJSON(b []byte) error { s, err := strconv.Unquote(string(b)) if err != nil { return err } return e.UnmarshalGQL(s) } func (e CriterionModifier) MarshalJSON() ([]byte, error) { var buf bytes.Buffer e.MarshalGQL(&buf) return buf.Bytes(), nil } type DateAccuracyEnum string const ( DateAccuracyEnumYear DateAccuracyEnum = "YEAR" DateAccuracyEnumMonth DateAccuracyEnum = "MONTH" DateAccuracyEnumDay DateAccuracyEnum = "DAY" ) var AllDateAccuracyEnum = []DateAccuracyEnum{ DateAccuracyEnumYear, DateAccuracyEnumMonth, DateAccuracyEnumDay, } func (e DateAccuracyEnum) IsValid() bool { switch e { case DateAccuracyEnumYear, DateAccuracyEnumMonth, DateAccuracyEnumDay: return true } return false } func (e DateAccuracyEnum) String() string { return string(e) } func (e *DateAccuracyEnum) UnmarshalGQL(v any) error { str, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } *e = DateAccuracyEnum(str) if !e.IsValid() { return fmt.Errorf("%s is not a valid DateAccuracyEnum", str) } return nil } func (e DateAccuracyEnum) MarshalGQL(w io.Writer) { fmt.Fprint(w, strconv.Quote(e.String())) } func (e *DateAccuracyEnum) UnmarshalJSON(b []byte) error { s, err := strconv.Unquote(string(b)) if err != nil { return err } return e.UnmarshalGQL(s) } func (e DateAccuracyEnum) MarshalJSON() ([]byte, error) { var buf bytes.Buffer e.MarshalGQL(&buf) return buf.Bytes(), nil } type EditSortEnum string const ( EditSortEnumCreatedAt EditSortEnum = "CREATED_AT" EditSortEnumUpdatedAt EditSortEnum = "UPDATED_AT" EditSortEnumClosedAt EditSortEnum = "CLOSED_AT" ) var AllEditSortEnum = []EditSortEnum{ EditSortEnumCreatedAt, EditSortEnumUpdatedAt, EditSortEnumClosedAt, } func (e EditSortEnum) IsValid() bool { switch e { case EditSortEnumCreatedAt, EditSortEnumUpdatedAt, EditSortEnumClosedAt: return true } return false } func (e EditSortEnum) String() string { return string(e) } func (e *EditSortEnum) UnmarshalGQL(v any) error { str, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } *e = EditSortEnum(str) if !e.IsValid() { return fmt.Errorf("%s is not a valid EditSortEnum", str) } return nil } func (e EditSortEnum) MarshalGQL(w io.Writer) { fmt.Fprint(w, strconv.Quote(e.String())) } func (e *EditSortEnum) UnmarshalJSON(b []byte) error { s, err := strconv.Unquote(string(b)) if err != nil { return err } return e.UnmarshalGQL(s) } func (e EditSortEnum) MarshalJSON() ([]byte, error) { var buf bytes.Buffer e.MarshalGQL(&buf) return buf.Bytes(), nil } type EthnicityEnum string const ( EthnicityEnumCaucasian EthnicityEnum = "CAUCASIAN" EthnicityEnumBlack EthnicityEnum = "BLACK" EthnicityEnumAsian EthnicityEnum = "ASIAN" EthnicityEnumIndian EthnicityEnum = "INDIAN" EthnicityEnumLatin EthnicityEnum = "LATIN" EthnicityEnumMiddleEastern EthnicityEnum = "MIDDLE_EASTERN" EthnicityEnumMixed EthnicityEnum = "MIXED" EthnicityEnumOther EthnicityEnum = "OTHER" ) var AllEthnicityEnum = []EthnicityEnum{ EthnicityEnumCaucasian, EthnicityEnumBlack, EthnicityEnumAsian, EthnicityEnumIndian, EthnicityEnumLatin, EthnicityEnumMiddleEastern, EthnicityEnumMixed, EthnicityEnumOther, } func (e EthnicityEnum) IsValid() bool { switch e { case EthnicityEnumCaucasian, EthnicityEnumBlack, EthnicityEnumAsian, EthnicityEnumIndian, EthnicityEnumLatin, EthnicityEnumMiddleEastern, EthnicityEnumMixed, EthnicityEnumOther: return true } return false } func (e EthnicityEnum) String() string { return string(e) } func (e *EthnicityEnum) UnmarshalGQL(v any) error { str, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } *e = EthnicityEnum(str) if !e.IsValid() { return fmt.Errorf("%s is not a valid EthnicityEnum", str) } return nil } func (e EthnicityEnum) MarshalGQL(w io.Writer) { fmt.Fprint(w, strconv.Quote(e.String())) } func (e *EthnicityEnum) UnmarshalJSON(b []byte) error { s, err := strconv.Unquote(string(b)) if err != nil { return err } return e.UnmarshalGQL(s) } func (e EthnicityEnum) MarshalJSON() ([]byte, error) { var buf bytes.Buffer e.MarshalGQL(&buf) return buf.Bytes(), nil } type EthnicityFilterEnum string const ( EthnicityFilterEnumUnknown EthnicityFilterEnum = "UNKNOWN" EthnicityFilterEnumCaucasian EthnicityFilterEnum = "CAUCASIAN" EthnicityFilterEnumBlack EthnicityFilterEnum = "BLACK" EthnicityFilterEnumAsian EthnicityFilterEnum = "ASIAN" EthnicityFilterEnumIndian EthnicityFilterEnum = "INDIAN" EthnicityFilterEnumLatin EthnicityFilterEnum = "LATIN" EthnicityFilterEnumMiddleEastern EthnicityFilterEnum = "MIDDLE_EASTERN" EthnicityFilterEnumMixed EthnicityFilterEnum = "MIXED" EthnicityFilterEnumOther EthnicityFilterEnum = "OTHER" ) var AllEthnicityFilterEnum = []EthnicityFilterEnum{ EthnicityFilterEnumUnknown, EthnicityFilterEnumCaucasian, EthnicityFilterEnumBlack, EthnicityFilterEnumAsian, EthnicityFilterEnumIndian, EthnicityFilterEnumLatin, EthnicityFilterEnumMiddleEastern, EthnicityFilterEnumMixed, EthnicityFilterEnumOther, } func (e EthnicityFilterEnum) IsValid() bool { switch e { case EthnicityFilterEnumUnknown, EthnicityFilterEnumCaucasian, EthnicityFilterEnumBlack, EthnicityFilterEnumAsian, EthnicityFilterEnumIndian, EthnicityFilterEnumLatin, EthnicityFilterEnumMiddleEastern, EthnicityFilterEnumMixed, EthnicityFilterEnumOther: return true } return false } func (e EthnicityFilterEnum) String() string { return string(e) } func (e *EthnicityFilterEnum) UnmarshalGQL(v any) error { str, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } *e = EthnicityFilterEnum(str) if !e.IsValid() { return fmt.Errorf("%s is not a valid EthnicityFilterEnum", str) } return nil } func (e EthnicityFilterEnum) MarshalGQL(w io.Writer) { fmt.Fprint(w, strconv.Quote(e.String())) } func (e *EthnicityFilterEnum) UnmarshalJSON(b []byte) error { s, err := strconv.Unquote(string(b)) if err != nil { return err } return e.UnmarshalGQL(s) } func (e EthnicityFilterEnum) MarshalJSON() ([]byte, error) { var buf bytes.Buffer e.MarshalGQL(&buf) return buf.Bytes(), nil } type EyeColorEnum string const ( EyeColorEnumBlue EyeColorEnum = "BLUE" EyeColorEnumBrown EyeColorEnum = "BROWN" EyeColorEnumGrey EyeColorEnum = "GREY" EyeColorEnumGreen EyeColorEnum = "GREEN" EyeColorEnumHazel EyeColorEnum = "HAZEL" EyeColorEnumRed EyeColorEnum = "RED" ) var AllEyeColorEnum = []EyeColorEnum{ EyeColorEnumBlue, EyeColorEnumBrown, EyeColorEnumGrey, EyeColorEnumGreen, EyeColorEnumHazel, EyeColorEnumRed, } func (e EyeColorEnum) IsValid() bool { switch e { case EyeColorEnumBlue, EyeColorEnumBrown, EyeColorEnumGrey, EyeColorEnumGreen, EyeColorEnumHazel, EyeColorEnumRed: return true } return false } func (e EyeColorEnum) String() string { return string(e) } func (e *EyeColorEnum) UnmarshalGQL(v any) error { str, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } *e = EyeColorEnum(str) if !e.IsValid() { return fmt.Errorf("%s is not a valid EyeColorEnum", str) } return nil } func (e EyeColorEnum) MarshalGQL(w io.Writer) { fmt.Fprint(w, strconv.Quote(e.String())) } func (e *EyeColorEnum) UnmarshalJSON(b []byte) error { s, err := strconv.Unquote(string(b)) if err != nil { return err } return e.UnmarshalGQL(s) } func (e EyeColorEnum) MarshalJSON() ([]byte, error) { var buf bytes.Buffer e.MarshalGQL(&buf) return buf.Bytes(), nil } type FavoriteFilter string const ( FavoriteFilterPerformer FavoriteFilter = "PERFORMER" FavoriteFilterStudio FavoriteFilter = "STUDIO" FavoriteFilterAll FavoriteFilter = "ALL" ) var AllFavoriteFilter = []FavoriteFilter{ FavoriteFilterPerformer, FavoriteFilterStudio, FavoriteFilterAll, } func (e FavoriteFilter) IsValid() bool { switch e { case FavoriteFilterPerformer, FavoriteFilterStudio, FavoriteFilterAll: return true } return false } func (e FavoriteFilter) String() string { return string(e) } func (e *FavoriteFilter) UnmarshalGQL(v any) error { str, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } *e = FavoriteFilter(str) if !e.IsValid() { return fmt.Errorf("%s is not a valid FavoriteFilter", str) } return nil } func (e FavoriteFilter) MarshalGQL(w io.Writer) { fmt.Fprint(w, strconv.Quote(e.String())) } func (e *FavoriteFilter) UnmarshalJSON(b []byte) error { s, err := strconv.Unquote(string(b)) if err != nil { return err } return e.UnmarshalGQL(s) } func (e FavoriteFilter) MarshalJSON() ([]byte, error) { var buf bytes.Buffer e.MarshalGQL(&buf) return buf.Bytes(), nil } type FingerprintAlgorithm string const ( FingerprintAlgorithmMd5 FingerprintAlgorithm = "MD5" FingerprintAlgorithmOshash FingerprintAlgorithm = "OSHASH" FingerprintAlgorithmPhash FingerprintAlgorithm = "PHASH" ) var AllFingerprintAlgorithm = []FingerprintAlgorithm{ FingerprintAlgorithmMd5, FingerprintAlgorithmOshash, FingerprintAlgorithmPhash, } func (e FingerprintAlgorithm) IsValid() bool { switch e { case FingerprintAlgorithmMd5, FingerprintAlgorithmOshash, FingerprintAlgorithmPhash: return true } return false } func (e FingerprintAlgorithm) String() string { return string(e) } func (e *FingerprintAlgorithm) UnmarshalGQL(v any) error { str, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } *e = FingerprintAlgorithm(str) if !e.IsValid() { return fmt.Errorf("%s is not a valid FingerprintAlgorithm", str) } return nil } func (e FingerprintAlgorithm) MarshalGQL(w io.Writer) { fmt.Fprint(w, strconv.Quote(e.String())) } func (e *FingerprintAlgorithm) UnmarshalJSON(b []byte) error { s, err := strconv.Unquote(string(b)) if err != nil { return err } return e.UnmarshalGQL(s) } func (e FingerprintAlgorithm) MarshalJSON() ([]byte, error) { var buf bytes.Buffer e.MarshalGQL(&buf) return buf.Bytes(), nil } type FingerprintSubmissionType string const ( // Positive vote FingerprintSubmissionTypeValid FingerprintSubmissionType = "VALID" // Report as invalid FingerprintSubmissionTypeInvalid FingerprintSubmissionType = "INVALID" // Remove vote FingerprintSubmissionTypeRemove FingerprintSubmissionType = "REMOVE" ) var AllFingerprintSubmissionType = []FingerprintSubmissionType{ FingerprintSubmissionTypeValid, FingerprintSubmissionTypeInvalid, FingerprintSubmissionTypeRemove, } func (e FingerprintSubmissionType) IsValid() bool { switch e { case FingerprintSubmissionTypeValid, FingerprintSubmissionTypeInvalid, FingerprintSubmissionTypeRemove: return true } return false } func (e FingerprintSubmissionType) String() string { return string(e) } func (e *FingerprintSubmissionType) UnmarshalGQL(v any) error { str, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } *e = FingerprintSubmissionType(str) if !e.IsValid() { return fmt.Errorf("%s is not a valid FingerprintSubmissionType", str) } return nil } func (e FingerprintSubmissionType) MarshalGQL(w io.Writer) { fmt.Fprint(w, strconv.Quote(e.String())) } func (e *FingerprintSubmissionType) UnmarshalJSON(b []byte) error { s, err := strconv.Unquote(string(b)) if err != nil { return err } return e.UnmarshalGQL(s) } func (e FingerprintSubmissionType) MarshalJSON() ([]byte, error) { var buf bytes.Buffer e.MarshalGQL(&buf) return buf.Bytes(), nil } type GenderEnum string const ( GenderEnumMale GenderEnum = "MALE" GenderEnumFemale GenderEnum = "FEMALE" GenderEnumTransgenderMale GenderEnum = "TRANSGENDER_MALE" GenderEnumTransgenderFemale GenderEnum = "TRANSGENDER_FEMALE" GenderEnumIntersex GenderEnum = "INTERSEX" GenderEnumNonBinary GenderEnum = "NON_BINARY" ) var AllGenderEnum = []GenderEnum{ GenderEnumMale, GenderEnumFemale, GenderEnumTransgenderMale, GenderEnumTransgenderFemale, GenderEnumIntersex, GenderEnumNonBinary, } func (e GenderEnum) IsValid() bool { switch e { case GenderEnumMale, GenderEnumFemale, GenderEnumTransgenderMale, GenderEnumTransgenderFemale, GenderEnumIntersex, GenderEnumNonBinary: return true } return false } func (e GenderEnum) String() string { return string(e) } func (e *GenderEnum) UnmarshalGQL(v any) error { str, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } *e = GenderEnum(str) if !e.IsValid() { return fmt.Errorf("%s is not a valid GenderEnum", str) } return nil } func (e GenderEnum) MarshalGQL(w io.Writer) { fmt.Fprint(w, strconv.Quote(e.String())) } func (e *GenderEnum) UnmarshalJSON(b []byte) error { s, err := strconv.Unquote(string(b)) if err != nil { return err } return e.UnmarshalGQL(s) } func (e GenderEnum) MarshalJSON() ([]byte, error) { var buf bytes.Buffer e.MarshalGQL(&buf) return buf.Bytes(), nil } type GenderFilterEnum string const ( GenderFilterEnumUnknown GenderFilterEnum = "UNKNOWN" GenderFilterEnumMale GenderFilterEnum = "MALE" GenderFilterEnumFemale GenderFilterEnum = "FEMALE" GenderFilterEnumTransgenderMale GenderFilterEnum = "TRANSGENDER_MALE" GenderFilterEnumTransgenderFemale GenderFilterEnum = "TRANSGENDER_FEMALE" GenderFilterEnumIntersex GenderFilterEnum = "INTERSEX" GenderFilterEnumNonBinary GenderFilterEnum = "NON_BINARY" ) var AllGenderFilterEnum = []GenderFilterEnum{ GenderFilterEnumUnknown, GenderFilterEnumMale, GenderFilterEnumFemale, GenderFilterEnumTransgenderMale, GenderFilterEnumTransgenderFemale, GenderFilterEnumIntersex, GenderFilterEnumNonBinary, } func (e GenderFilterEnum) IsValid() bool { switch e { case GenderFilterEnumUnknown, GenderFilterEnumMale, GenderFilterEnumFemale, GenderFilterEnumTransgenderMale, GenderFilterEnumTransgenderFemale, GenderFilterEnumIntersex, GenderFilterEnumNonBinary: return true } return false } func (e GenderFilterEnum) String() string { return string(e) } func (e *GenderFilterEnum) UnmarshalGQL(v any) error { str, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } *e = GenderFilterEnum(str) if !e.IsValid() { return fmt.Errorf("%s is not a valid GenderFilterEnum", str) } return nil } func (e GenderFilterEnum) MarshalGQL(w io.Writer) { fmt.Fprint(w, strconv.Quote(e.String())) } func (e *GenderFilterEnum) UnmarshalJSON(b []byte) error { s, err := strconv.Unquote(string(b)) if err != nil { return err } return e.UnmarshalGQL(s) } func (e GenderFilterEnum) MarshalJSON() ([]byte, error) { var buf bytes.Buffer e.MarshalGQL(&buf) return buf.Bytes(), nil } type HairColorEnum string const ( HairColorEnumBlonde HairColorEnum = "BLONDE" HairColorEnumBrunette HairColorEnum = "BRUNETTE" HairColorEnumBlack HairColorEnum = "BLACK" HairColorEnumRed HairColorEnum = "RED" HairColorEnumAuburn HairColorEnum = "AUBURN" HairColorEnumGrey HairColorEnum = "GREY" HairColorEnumBald HairColorEnum = "BALD" HairColorEnumVarious HairColorEnum = "VARIOUS" HairColorEnumWhite HairColorEnum = "WHITE" HairColorEnumOther HairColorEnum = "OTHER" ) var AllHairColorEnum = []HairColorEnum{ HairColorEnumBlonde, HairColorEnumBrunette, HairColorEnumBlack, HairColorEnumRed, HairColorEnumAuburn, HairColorEnumGrey, HairColorEnumBald, HairColorEnumVarious, HairColorEnumWhite, HairColorEnumOther, } func (e HairColorEnum) IsValid() bool { switch e { case HairColorEnumBlonde, HairColorEnumBrunette, HairColorEnumBlack, HairColorEnumRed, HairColorEnumAuburn, HairColorEnumGrey, HairColorEnumBald, HairColorEnumVarious, HairColorEnumWhite, HairColorEnumOther: return true } return false } func (e HairColorEnum) String() string { return string(e) } func (e *HairColorEnum) UnmarshalGQL(v any) error { str, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } *e = HairColorEnum(str) if !e.IsValid() { return fmt.Errorf("%s is not a valid HairColorEnum", str) } return nil } func (e HairColorEnum) MarshalGQL(w io.Writer) { fmt.Fprint(w, strconv.Quote(e.String())) } func (e *HairColorEnum) UnmarshalJSON(b []byte) error { s, err := strconv.Unquote(string(b)) if err != nil { return err } return e.UnmarshalGQL(s) } func (e HairColorEnum) MarshalJSON() ([]byte, error) { var buf bytes.Buffer e.MarshalGQL(&buf) return buf.Bytes(), nil } type ModAuditActionEnum string const ( ModAuditActionEnumEditDelete ModAuditActionEnum = "EDIT_DELETE" ModAuditActionEnumEditAmendment ModAuditActionEnum = "EDIT_AMENDMENT" ) var AllModAuditActionEnum = []ModAuditActionEnum{ ModAuditActionEnumEditDelete, ModAuditActionEnumEditAmendment, } func (e ModAuditActionEnum) IsValid() bool { switch e { case ModAuditActionEnumEditDelete, ModAuditActionEnumEditAmendment: return true } return false } func (e ModAuditActionEnum) String() string { return string(e) } func (e *ModAuditActionEnum) UnmarshalGQL(v any) error { str, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } *e = ModAuditActionEnum(str) if !e.IsValid() { return fmt.Errorf("%s is not a valid ModAuditActionEnum", str) } return nil } func (e ModAuditActionEnum) MarshalGQL(w io.Writer) { fmt.Fprint(w, strconv.Quote(e.String())) } func (e *ModAuditActionEnum) UnmarshalJSON(b []byte) error { s, err := strconv.Unquote(string(b)) if err != nil { return err } return e.UnmarshalGQL(s) } func (e ModAuditActionEnum) MarshalJSON() ([]byte, error) { var buf bytes.Buffer e.MarshalGQL(&buf) return buf.Bytes(), nil } type NotificationEnum string const ( NotificationEnumFavoritePerformerScene NotificationEnum = "FAVORITE_PERFORMER_SCENE" NotificationEnumFavoritePerformerEdit NotificationEnum = "FAVORITE_PERFORMER_EDIT" NotificationEnumFavoriteStudioScene NotificationEnum = "FAVORITE_STUDIO_SCENE" NotificationEnumFavoriteStudioEdit NotificationEnum = "FAVORITE_STUDIO_EDIT" NotificationEnumCommentOwnEdit NotificationEnum = "COMMENT_OWN_EDIT" NotificationEnumDownvoteOwnEdit NotificationEnum = "DOWNVOTE_OWN_EDIT" NotificationEnumFailedOwnEdit NotificationEnum = "FAILED_OWN_EDIT" NotificationEnumCommentCommentedEdit NotificationEnum = "COMMENT_COMMENTED_EDIT" NotificationEnumCommentVotedEdit NotificationEnum = "COMMENT_VOTED_EDIT" NotificationEnumUpdatedEdit NotificationEnum = "UPDATED_EDIT" NotificationEnumFingerprintedSceneEdit NotificationEnum = "FINGERPRINTED_SCENE_EDIT" ) var AllNotificationEnum = []NotificationEnum{ NotificationEnumFavoritePerformerScene, NotificationEnumFavoritePerformerEdit, NotificationEnumFavoriteStudioScene, NotificationEnumFavoriteStudioEdit, NotificationEnumCommentOwnEdit, NotificationEnumDownvoteOwnEdit, NotificationEnumFailedOwnEdit, NotificationEnumCommentCommentedEdit, NotificationEnumCommentVotedEdit, NotificationEnumUpdatedEdit, NotificationEnumFingerprintedSceneEdit, } func (e NotificationEnum) IsValid() bool { switch e { case NotificationEnumFavoritePerformerScene, NotificationEnumFavoritePerformerEdit, NotificationEnumFavoriteStudioScene, NotificationEnumFavoriteStudioEdit, NotificationEnumCommentOwnEdit, NotificationEnumDownvoteOwnEdit, NotificationEnumFailedOwnEdit, NotificationEnumCommentCommentedEdit, NotificationEnumCommentVotedEdit, NotificationEnumUpdatedEdit, NotificationEnumFingerprintedSceneEdit: return true } return false } func (e NotificationEnum) String() string { return string(e) } func (e *NotificationEnum) UnmarshalGQL(v any) error { str, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } *e = NotificationEnum(str) if !e.IsValid() { return fmt.Errorf("%s is not a valid NotificationEnum", str) } return nil } func (e NotificationEnum) MarshalGQL(w io.Writer) { fmt.Fprint(w, strconv.Quote(e.String())) } func (e *NotificationEnum) UnmarshalJSON(b []byte) error { s, err := strconv.Unquote(string(b)) if err != nil { return err } return e.UnmarshalGQL(s) } func (e NotificationEnum) MarshalJSON() ([]byte, error) { var buf bytes.Buffer e.MarshalGQL(&buf) return buf.Bytes(), nil } type OperationEnum string const ( OperationEnumCreate OperationEnum = "CREATE" OperationEnumModify OperationEnum = "MODIFY" OperationEnumDestroy OperationEnum = "DESTROY" OperationEnumMerge OperationEnum = "MERGE" ) var AllOperationEnum = []OperationEnum{ OperationEnumCreate, OperationEnumModify, OperationEnumDestroy, OperationEnumMerge, } func (e OperationEnum) IsValid() bool { switch e { case OperationEnumCreate, OperationEnumModify, OperationEnumDestroy, OperationEnumMerge: return true } return false } func (e OperationEnum) String() string { return string(e) } func (e *OperationEnum) UnmarshalGQL(v any) error { str, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } *e = OperationEnum(str) if !e.IsValid() { return fmt.Errorf("%s is not a valid OperationEnum", str) } return nil } func (e OperationEnum) MarshalGQL(w io.Writer) { fmt.Fprint(w, strconv.Quote(e.String())) } func (e *OperationEnum) UnmarshalJSON(b []byte) error { s, err := strconv.Unquote(string(b)) if err != nil { return err } return e.UnmarshalGQL(s) } func (e OperationEnum) MarshalJSON() ([]byte, error) { var buf bytes.Buffer e.MarshalGQL(&buf) return buf.Bytes(), nil } type PerformerSortEnum string const ( PerformerSortEnumName PerformerSortEnum = "NAME" PerformerSortEnumBirthdate PerformerSortEnum = "BIRTHDATE" PerformerSortEnumDeathdate PerformerSortEnum = "DEATHDATE" PerformerSortEnumSceneCount PerformerSortEnum = "SCENE_COUNT" PerformerSortEnumCareerStartYear PerformerSortEnum = "CAREER_START_YEAR" PerformerSortEnumDebut PerformerSortEnum = "DEBUT" PerformerSortEnumLastScene PerformerSortEnum = "LAST_SCENE" PerformerSortEnumCreatedAt PerformerSortEnum = "CREATED_AT" PerformerSortEnumUpdatedAt PerformerSortEnum = "UPDATED_AT" ) var AllPerformerSortEnum = []PerformerSortEnum{ PerformerSortEnumName, PerformerSortEnumBirthdate, PerformerSortEnumDeathdate, PerformerSortEnumSceneCount, PerformerSortEnumCareerStartYear, PerformerSortEnumDebut, PerformerSortEnumLastScene, PerformerSortEnumCreatedAt, PerformerSortEnumUpdatedAt, } func (e PerformerSortEnum) IsValid() bool { switch e { case PerformerSortEnumName, PerformerSortEnumBirthdate, PerformerSortEnumDeathdate, PerformerSortEnumSceneCount, PerformerSortEnumCareerStartYear, PerformerSortEnumDebut, PerformerSortEnumLastScene, PerformerSortEnumCreatedAt, PerformerSortEnumUpdatedAt: return true } return false } func (e PerformerSortEnum) String() string { return string(e) } func (e *PerformerSortEnum) UnmarshalGQL(v any) error { str, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } *e = PerformerSortEnum(str) if !e.IsValid() { return fmt.Errorf("%s is not a valid PerformerSortEnum", str) } return nil } func (e PerformerSortEnum) MarshalGQL(w io.Writer) { fmt.Fprint(w, strconv.Quote(e.String())) } func (e *PerformerSortEnum) UnmarshalJSON(b []byte) error { s, err := strconv.Unquote(string(b)) if err != nil { return err } return e.UnmarshalGQL(s) } func (e PerformerSortEnum) MarshalJSON() ([]byte, error) { var buf bytes.Buffer e.MarshalGQL(&buf) return buf.Bytes(), nil } type RoleEnum string const ( RoleEnumRead RoleEnum = "READ" RoleEnumVote RoleEnum = "VOTE" RoleEnumEdit RoleEnum = "EDIT" RoleEnumModify RoleEnum = "MODIFY" RoleEnumModerate RoleEnum = "MODERATE" RoleEnumAdmin RoleEnum = "ADMIN" // May generate invites without tokens RoleEnumInvite RoleEnum = "INVITE" // May grant and rescind invite tokens and resind invite keys RoleEnumManageInvites RoleEnum = "MANAGE_INVITES" RoleEnumBot RoleEnum = "BOT" RoleEnumReadOnly RoleEnum = "READ_ONLY" RoleEnumEditTags RoleEnum = "EDIT_TAGS" ) var AllRoleEnum = []RoleEnum{ RoleEnumRead, RoleEnumVote, RoleEnumEdit, RoleEnumModify, RoleEnumModerate, RoleEnumAdmin, RoleEnumInvite, RoleEnumManageInvites, RoleEnumBot, RoleEnumReadOnly, RoleEnumEditTags, } func (e RoleEnum) IsValid() bool { switch e { case RoleEnumRead, RoleEnumVote, RoleEnumEdit, RoleEnumModify, RoleEnumModerate, RoleEnumAdmin, RoleEnumInvite, RoleEnumManageInvites, RoleEnumBot, RoleEnumReadOnly, RoleEnumEditTags: return true } return false } func (e RoleEnum) String() string { return string(e) } func (e *RoleEnum) UnmarshalGQL(v any) error { str, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } *e = RoleEnum(str) if !e.IsValid() { return fmt.Errorf("%s is not a valid RoleEnum", str) } return nil } func (e RoleEnum) MarshalGQL(w io.Writer) { fmt.Fprint(w, strconv.Quote(e.String())) } func (e *RoleEnum) UnmarshalJSON(b []byte) error { s, err := strconv.Unquote(string(b)) if err != nil { return err } return e.UnmarshalGQL(s) } func (e RoleEnum) MarshalJSON() ([]byte, error) { var buf bytes.Buffer e.MarshalGQL(&buf) return buf.Bytes(), nil } type SceneSortEnum string const ( SceneSortEnumTitle SceneSortEnum = "TITLE" SceneSortEnumDate SceneSortEnum = "DATE" SceneSortEnumTrending SceneSortEnum = "TRENDING" SceneSortEnumCreatedAt SceneSortEnum = "CREATED_AT" SceneSortEnumUpdatedAt SceneSortEnum = "UPDATED_AT" ) var AllSceneSortEnum = []SceneSortEnum{ SceneSortEnumTitle, SceneSortEnumDate, SceneSortEnumTrending, SceneSortEnumCreatedAt, SceneSortEnumUpdatedAt, } func (e SceneSortEnum) IsValid() bool { switch e { case SceneSortEnumTitle, SceneSortEnumDate, SceneSortEnumTrending, SceneSortEnumCreatedAt, SceneSortEnumUpdatedAt: return true } return false } func (e SceneSortEnum) String() string { return string(e) } func (e *SceneSortEnum) UnmarshalGQL(v any) error { str, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } *e = SceneSortEnum(str) if !e.IsValid() { return fmt.Errorf("%s is not a valid SceneSortEnum", str) } return nil } func (e SceneSortEnum) MarshalGQL(w io.Writer) { fmt.Fprint(w, strconv.Quote(e.String())) } func (e *SceneSortEnum) UnmarshalJSON(b []byte) error { s, err := strconv.Unquote(string(b)) if err != nil { return err } return e.UnmarshalGQL(s) } func (e SceneSortEnum) MarshalJSON() ([]byte, error) { var buf bytes.Buffer e.MarshalGQL(&buf) return buf.Bytes(), nil } type SortDirectionEnum string const ( SortDirectionEnumAsc SortDirectionEnum = "ASC" SortDirectionEnumDesc SortDirectionEnum = "DESC" ) var AllSortDirectionEnum = []SortDirectionEnum{ SortDirectionEnumAsc, SortDirectionEnumDesc, } func (e SortDirectionEnum) IsValid() bool { switch e { case SortDirectionEnumAsc, SortDirectionEnumDesc: return true } return false } func (e SortDirectionEnum) String() string { return string(e) } func (e *SortDirectionEnum) UnmarshalGQL(v any) error { str, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } *e = SortDirectionEnum(str) if !e.IsValid() { return fmt.Errorf("%s is not a valid SortDirectionEnum", str) } return nil } func (e SortDirectionEnum) MarshalGQL(w io.Writer) { fmt.Fprint(w, strconv.Quote(e.String())) } func (e *SortDirectionEnum) UnmarshalJSON(b []byte) error { s, err := strconv.Unquote(string(b)) if err != nil { return err } return e.UnmarshalGQL(s) } func (e SortDirectionEnum) MarshalJSON() ([]byte, error) { var buf bytes.Buffer e.MarshalGQL(&buf) return buf.Bytes(), nil } type StudioSortEnum string const ( StudioSortEnumName StudioSortEnum = "NAME" StudioSortEnumCreatedAt StudioSortEnum = "CREATED_AT" StudioSortEnumUpdatedAt StudioSortEnum = "UPDATED_AT" ) var AllStudioSortEnum = []StudioSortEnum{ StudioSortEnumName, StudioSortEnumCreatedAt, StudioSortEnumUpdatedAt, } func (e StudioSortEnum) IsValid() bool { switch e { case StudioSortEnumName, StudioSortEnumCreatedAt, StudioSortEnumUpdatedAt: return true } return false } func (e StudioSortEnum) String() string { return string(e) } func (e *StudioSortEnum) UnmarshalGQL(v any) error { str, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } *e = StudioSortEnum(str) if !e.IsValid() { return fmt.Errorf("%s is not a valid StudioSortEnum", str) } return nil } func (e StudioSortEnum) MarshalGQL(w io.Writer) { fmt.Fprint(w, strconv.Quote(e.String())) } func (e *StudioSortEnum) UnmarshalJSON(b []byte) error { s, err := strconv.Unquote(string(b)) if err != nil { return err } return e.UnmarshalGQL(s) } func (e StudioSortEnum) MarshalJSON() ([]byte, error) { var buf bytes.Buffer e.MarshalGQL(&buf) return buf.Bytes(), nil } type TagGroupEnum string const ( TagGroupEnumPeople TagGroupEnum = "PEOPLE" TagGroupEnumScene TagGroupEnum = "SCENE" TagGroupEnumAction TagGroupEnum = "ACTION" ) var AllTagGroupEnum = []TagGroupEnum{ TagGroupEnumPeople, TagGroupEnumScene, TagGroupEnumAction, } func (e TagGroupEnum) IsValid() bool { switch e { case TagGroupEnumPeople, TagGroupEnumScene, TagGroupEnumAction: return true } return false } func (e TagGroupEnum) String() string { return string(e) } func (e *TagGroupEnum) UnmarshalGQL(v any) error { str, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } *e = TagGroupEnum(str) if !e.IsValid() { return fmt.Errorf("%s is not a valid TagGroupEnum", str) } return nil } func (e TagGroupEnum) MarshalGQL(w io.Writer) { fmt.Fprint(w, strconv.Quote(e.String())) } func (e *TagGroupEnum) UnmarshalJSON(b []byte) error { s, err := strconv.Unquote(string(b)) if err != nil { return err } return e.UnmarshalGQL(s) } func (e TagGroupEnum) MarshalJSON() ([]byte, error) { var buf bytes.Buffer e.MarshalGQL(&buf) return buf.Bytes(), nil } type TagSortEnum string const ( TagSortEnumName TagSortEnum = "NAME" TagSortEnumCreatedAt TagSortEnum = "CREATED_AT" TagSortEnumUpdatedAt TagSortEnum = "UPDATED_AT" ) var AllTagSortEnum = []TagSortEnum{ TagSortEnumName, TagSortEnumCreatedAt, TagSortEnumUpdatedAt, } func (e TagSortEnum) IsValid() bool { switch e { case TagSortEnumName, TagSortEnumCreatedAt, TagSortEnumUpdatedAt: return true } return false } func (e TagSortEnum) String() string { return string(e) } func (e *TagSortEnum) UnmarshalGQL(v any) error { str, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } *e = TagSortEnum(str) if !e.IsValid() { return fmt.Errorf("%s is not a valid TagSortEnum", str) } return nil } func (e TagSortEnum) MarshalGQL(w io.Writer) { fmt.Fprint(w, strconv.Quote(e.String())) } func (e *TagSortEnum) UnmarshalJSON(b []byte) error { s, err := strconv.Unquote(string(b)) if err != nil { return err } return e.UnmarshalGQL(s) } func (e TagSortEnum) MarshalJSON() ([]byte, error) { var buf bytes.Buffer e.MarshalGQL(&buf) return buf.Bytes(), nil } type TargetTypeEnum string const ( TargetTypeEnumScene TargetTypeEnum = "SCENE" TargetTypeEnumStudio TargetTypeEnum = "STUDIO" TargetTypeEnumPerformer TargetTypeEnum = "PERFORMER" TargetTypeEnumTag TargetTypeEnum = "TAG" ) var AllTargetTypeEnum = []TargetTypeEnum{ TargetTypeEnumScene, TargetTypeEnumStudio, TargetTypeEnumPerformer, TargetTypeEnumTag, } func (e TargetTypeEnum) IsValid() bool { switch e { case TargetTypeEnumScene, TargetTypeEnumStudio, TargetTypeEnumPerformer, TargetTypeEnumTag: return true } return false } func (e TargetTypeEnum) String() string { return string(e) } func (e *TargetTypeEnum) UnmarshalGQL(v any) error { str, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } *e = TargetTypeEnum(str) if !e.IsValid() { return fmt.Errorf("%s is not a valid TargetTypeEnum", str) } return nil } func (e TargetTypeEnum) MarshalGQL(w io.Writer) { fmt.Fprint(w, strconv.Quote(e.String())) } func (e *TargetTypeEnum) UnmarshalJSON(b []byte) error { s, err := strconv.Unquote(string(b)) if err != nil { return err } return e.UnmarshalGQL(s) } func (e TargetTypeEnum) MarshalJSON() ([]byte, error) { var buf bytes.Buffer e.MarshalGQL(&buf) return buf.Bytes(), nil } type UserChangeEmailStatus string const ( UserChangeEmailStatusConfirmOld UserChangeEmailStatus = "CONFIRM_OLD" UserChangeEmailStatusConfirmNew UserChangeEmailStatus = "CONFIRM_NEW" UserChangeEmailStatusExpired UserChangeEmailStatus = "EXPIRED" UserChangeEmailStatusInvalidToken UserChangeEmailStatus = "INVALID_TOKEN" UserChangeEmailStatusSuccess UserChangeEmailStatus = "SUCCESS" UserChangeEmailStatusError UserChangeEmailStatus = "ERROR" ) var AllUserChangeEmailStatus = []UserChangeEmailStatus{ UserChangeEmailStatusConfirmOld, UserChangeEmailStatusConfirmNew, UserChangeEmailStatusExpired, UserChangeEmailStatusInvalidToken, UserChangeEmailStatusSuccess, UserChangeEmailStatusError, } func (e UserChangeEmailStatus) IsValid() bool { switch e { case UserChangeEmailStatusConfirmOld, UserChangeEmailStatusConfirmNew, UserChangeEmailStatusExpired, UserChangeEmailStatusInvalidToken, UserChangeEmailStatusSuccess, UserChangeEmailStatusError: return true } return false } func (e UserChangeEmailStatus) String() string { return string(e) } func (e *UserChangeEmailStatus) UnmarshalGQL(v any) error { str, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } *e = UserChangeEmailStatus(str) if !e.IsValid() { return fmt.Errorf("%s is not a valid UserChangeEmailStatus", str) } return nil } func (e UserChangeEmailStatus) MarshalGQL(w io.Writer) { fmt.Fprint(w, strconv.Quote(e.String())) } func (e *UserChangeEmailStatus) UnmarshalJSON(b []byte) error { s, err := strconv.Unquote(string(b)) if err != nil { return err } return e.UnmarshalGQL(s) } func (e UserChangeEmailStatus) MarshalJSON() ([]byte, error) { var buf bytes.Buffer e.MarshalGQL(&buf) return buf.Bytes(), nil } type UserVotedFilterEnum string const ( UserVotedFilterEnumAbstain UserVotedFilterEnum = "ABSTAIN" UserVotedFilterEnumAccept UserVotedFilterEnum = "ACCEPT" UserVotedFilterEnumReject UserVotedFilterEnum = "REJECT" UserVotedFilterEnumNotVoted UserVotedFilterEnum = "NOT_VOTED" ) var AllUserVotedFilterEnum = []UserVotedFilterEnum{ UserVotedFilterEnumAbstain, UserVotedFilterEnumAccept, UserVotedFilterEnumReject, UserVotedFilterEnumNotVoted, } func (e UserVotedFilterEnum) IsValid() bool { switch e { case UserVotedFilterEnumAbstain, UserVotedFilterEnumAccept, UserVotedFilterEnumReject, UserVotedFilterEnumNotVoted: return true } return false } func (e UserVotedFilterEnum) String() string { return string(e) } func (e *UserVotedFilterEnum) UnmarshalGQL(v any) error { str, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } *e = UserVotedFilterEnum(str) if !e.IsValid() { return fmt.Errorf("%s is not a valid UserVotedFilterEnum", str) } return nil } func (e UserVotedFilterEnum) MarshalGQL(w io.Writer) { fmt.Fprint(w, strconv.Quote(e.String())) } func (e *UserVotedFilterEnum) UnmarshalJSON(b []byte) error { s, err := strconv.Unquote(string(b)) if err != nil { return err } return e.UnmarshalGQL(s) } func (e UserVotedFilterEnum) MarshalJSON() ([]byte, error) { var buf bytes.Buffer e.MarshalGQL(&buf) return buf.Bytes(), nil } type ValidSiteTypeEnum string const ( ValidSiteTypeEnumPerformer ValidSiteTypeEnum = "PERFORMER" ValidSiteTypeEnumScene ValidSiteTypeEnum = "SCENE" ValidSiteTypeEnumStudio ValidSiteTypeEnum = "STUDIO" ) var AllValidSiteTypeEnum = []ValidSiteTypeEnum{ ValidSiteTypeEnumPerformer, ValidSiteTypeEnumScene, ValidSiteTypeEnumStudio, } func (e ValidSiteTypeEnum) IsValid() bool { switch e { case ValidSiteTypeEnumPerformer, ValidSiteTypeEnumScene, ValidSiteTypeEnumStudio: return true } return false } func (e ValidSiteTypeEnum) String() string { return string(e) } func (e *ValidSiteTypeEnum) UnmarshalGQL(v any) error { str, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } *e = ValidSiteTypeEnum(str) if !e.IsValid() { return fmt.Errorf("%s is not a valid ValidSiteTypeEnum", str) } return nil } func (e ValidSiteTypeEnum) MarshalGQL(w io.Writer) { fmt.Fprint(w, strconv.Quote(e.String())) } func (e *ValidSiteTypeEnum) UnmarshalJSON(b []byte) error { s, err := strconv.Unquote(string(b)) if err != nil { return err } return e.UnmarshalGQL(s) } func (e ValidSiteTypeEnum) MarshalJSON() ([]byte, error) { var buf bytes.Buffer e.MarshalGQL(&buf) return buf.Bytes(), nil } type VoteStatusEnum string const ( VoteStatusEnumAccepted VoteStatusEnum = "ACCEPTED" VoteStatusEnumRejected VoteStatusEnum = "REJECTED" VoteStatusEnumPending VoteStatusEnum = "PENDING" VoteStatusEnumImmediateAccepted VoteStatusEnum = "IMMEDIATE_ACCEPTED" VoteStatusEnumImmediateRejected VoteStatusEnum = "IMMEDIATE_REJECTED" VoteStatusEnumFailed VoteStatusEnum = "FAILED" VoteStatusEnumCanceled VoteStatusEnum = "CANCELED" ) var AllVoteStatusEnum = []VoteStatusEnum{ VoteStatusEnumAccepted, VoteStatusEnumRejected, VoteStatusEnumPending, VoteStatusEnumImmediateAccepted, VoteStatusEnumImmediateRejected, VoteStatusEnumFailed, VoteStatusEnumCanceled, } func (e VoteStatusEnum) IsValid() bool { switch e { case VoteStatusEnumAccepted, VoteStatusEnumRejected, VoteStatusEnumPending, VoteStatusEnumImmediateAccepted, VoteStatusEnumImmediateRejected, VoteStatusEnumFailed, VoteStatusEnumCanceled: return true } return false } func (e VoteStatusEnum) String() string { return string(e) } func (e *VoteStatusEnum) UnmarshalGQL(v any) error { str, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } *e = VoteStatusEnum(str) if !e.IsValid() { return fmt.Errorf("%s is not a valid VoteStatusEnum", str) } return nil } func (e VoteStatusEnum) MarshalGQL(w io.Writer) { fmt.Fprint(w, strconv.Quote(e.String())) } func (e *VoteStatusEnum) UnmarshalJSON(b []byte) error { s, err := strconv.Unquote(string(b)) if err != nil { return err } return e.UnmarshalGQL(s) } func (e VoteStatusEnum) MarshalJSON() ([]byte, error) { var buf bytes.Buffer e.MarshalGQL(&buf) return buf.Bytes(), nil } type VoteTypeEnum string const ( VoteTypeEnumAbstain VoteTypeEnum = "ABSTAIN" VoteTypeEnumAccept VoteTypeEnum = "ACCEPT" VoteTypeEnumReject VoteTypeEnum = "REJECT" // Immediately accepts the edit - bypassing the vote VoteTypeEnumImmediateAccept VoteTypeEnum = "IMMEDIATE_ACCEPT" // Immediately rejects the edit - bypassing the vote VoteTypeEnumImmediateReject VoteTypeEnum = "IMMEDIATE_REJECT" ) var AllVoteTypeEnum = []VoteTypeEnum{ VoteTypeEnumAbstain, VoteTypeEnumAccept, VoteTypeEnumReject, VoteTypeEnumImmediateAccept, VoteTypeEnumImmediateReject, } func (e VoteTypeEnum) IsValid() bool { switch e { case VoteTypeEnumAbstain, VoteTypeEnumAccept, VoteTypeEnumReject, VoteTypeEnumImmediateAccept, VoteTypeEnumImmediateReject: return true } return false } func (e VoteTypeEnum) String() string { return string(e) } func (e *VoteTypeEnum) UnmarshalGQL(v any) error { str, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } *e = VoteTypeEnum(str) if !e.IsValid() { return fmt.Errorf("%s is not a valid VoteTypeEnum", str) } return nil } func (e VoteTypeEnum) MarshalGQL(w io.Writer) { fmt.Fprint(w, strconv.Quote(e.String())) } func (e *VoteTypeEnum) UnmarshalJSON(b []byte) error { s, err := strconv.Unquote(string(b)) if err != nil { return err } return e.UnmarshalGQL(s) } func (e VoteTypeEnum) MarshalJSON() ([]byte, error) { var buf bytes.Buffer e.MarshalGQL(&buf) return buf.Bytes(), nil } ================================================ FILE: internal/models/model_draft.go ================================================ package models import ( "encoding/json" "time" "github.com/gofrs/uuid" ) type Draft struct { ID uuid.UUID `db:"id" json:"id"` UserID uuid.UUID `db:"user_id" json:"user_id"` Type string `db:"type" json:"type"` Data json.RawMessage `db:"data" json:"data"` CreatedAt time.Time `db:"created_at" json:"created_at"` } type DraftEntity struct { Name string `json:"name"` ID *uuid.UUID `json:"id,omitempty"` } func (DraftEntity) IsSceneDraftTag() {} func (DraftEntity) IsSceneDraftPerformer() {} func (DraftEntity) IsSceneDraftStudio() {} type SceneDraft struct { ID *uuid.UUID `json:"id,omitempty"` Title *string `json:"title,omitempty"` Code *string `json:"code,omitempty"` Details *string `json:"details,omitempty"` Director *string `json:"director,omitempty"` URLs []string `json:"urls,omitempty"` Date *string `json:"date,omitempty"` ProductionDate *string `json:"production_date,omitempty"` Studio *DraftEntity `json:"studio,omitempty"` Performers []DraftEntity `json:"performers,omitempty"` Tags []DraftEntity `json:"tags,omitempty"` Image *uuid.UUID `json:"image,omitempty"` Fingerprints []DraftFingerprint `json:"fingerprints"` } func (SceneDraft) IsDraftData() {} type PerformerDraft struct { ID *uuid.UUID `json:"id,omitempty"` Name string `json:"name"` Disambiguation *string `json:"disambiguation,omitempty"` Aliases *string `json:"aliases,omitempty"` Gender *string `json:"gender,omitempty"` Birthdate *string `json:"birthdate,omitempty"` Deathdate *string `json:"deathdate,omitempty"` Urls []string `json:"urls,omitempty"` Ethnicity *string `json:"ethnicity,omitempty"` Country *string `json:"country,omitempty"` EyeColor *string `json:"eye_color,omitempty"` HairColor *string `json:"hair_color,omitempty"` Height *string `json:"height,omitempty"` Measurements *string `json:"measurements,omitempty"` BreastType *string `json:"breast_type,omitempty"` Tattoos *string `json:"tattoos,omitempty"` Piercings *string `json:"piercings,omitempty"` CareerStartYear *int `json:"career_start_year,omitempty"` CareerEndYear *int `json:"career_end_year,omitempty"` Image *uuid.UUID `json:"image,omitempty"` } func (PerformerDraft) IsDraftData() {} func (e *Draft) GetPerformerData() (*PerformerDraft, error) { data := PerformerDraft{} err := json.Unmarshal(e.Data, &data) return &data, err } func (e *Draft) GetSceneData() (*SceneDraft, error) { data := SceneDraft{} err := json.Unmarshal(e.Data, &data) return &data, err } ================================================ FILE: internal/models/model_edit.go ================================================ package models import ( "bytes" "encoding/json" "strings" "time" "github.com/gofrs/uuid" ) type Edit struct { ID uuid.UUID `json:"id"` UserID uuid.NullUUID `json:"user_id"` TargetType string `json:"target_type"` Operation string `json:"operation"` VoteCount int `json:"votes"` Status string `json:"status"` Applied bool `json:"applied"` Data json.RawMessage `json:"data"` Bot bool `json:"bot"` CreatedAt time.Time `json:"created_at"` UpdateCount int `json:"update_count"` UpdatedAt *time.Time `json:"updated_at"` ClosedAt *time.Time `json:"closed_at"` } type EditComment struct { ID uuid.UUID `json:"id"` EditID uuid.UUID `json:"edit_id"` UserID uuid.NullUUID `json:"user_id"` CreatedAt time.Time `json:"created_at"` Text string `json:"text"` } type EditVote struct { EditID uuid.UUID `json:"edit_id"` UserID uuid.UUID `json:"user_id"` CreatedAt time.Time `json:"created_at"` Vote string `json:"vote"` } func NewEdit(id uuid.UUID, user *User, targetType TargetTypeEnum, input *EditInput) *Edit { userID := uuid.NullUUID{UUID: user.ID, Valid: true} ret := &Edit{ ID: id, UserID: userID, TargetType: targetType.String(), Status: VoteStatusEnumPending.String(), Operation: input.Operation.String(), } if input.Bot != nil && *input.Bot { ret.Bot = true } else { ret.Bot = false } return ret } func NewEditComment(id uuid.UUID, userID uuid.UUID, edit *Edit, text string) *EditComment { ret := &EditComment{ ID: id, EditID: edit.ID, UserID: uuid.NullUUID{UUID: userID, Valid: true}, Text: text, } return ret } func (e *Edit) Accept() { e.Status = VoteStatusEnumAccepted.String() e.Applied = true now := time.Now() e.ClosedAt = &now } func (e *Edit) ImmediateAccept() { e.Status = VoteStatusEnumImmediateAccepted.String() e.Applied = true now := time.Now() e.ClosedAt = &now } func (e *Edit) ImmediateReject() { e.Status = VoteStatusEnumImmediateRejected.String() now := time.Now() e.ClosedAt = &now } func (e *Edit) Reject() { e.Status = VoteStatusEnumRejected.String() now := time.Now() e.ClosedAt = &now } func (e *Edit) Fail() { e.Status = VoteStatusEnumFailed.String() now := time.Now() e.ClosedAt = &now } func (e *Edit) Cancel() { e.Status = VoteStatusEnumCanceled.String() now := time.Now() e.ClosedAt = &now } func (e *Edit) SetData(data any) error { buffer := &bytes.Buffer{} encoder := json.NewEncoder(buffer) encoder.SetEscapeHTML(false) encoder.SetIndent("", " ") if err := encoder.Encode(data); err != nil { return err } e.Data = buffer.Bytes() return nil } type EditData struct { New *json.RawMessage `json:"new_data,omitempty"` Old *json.RawMessage `json:"old_data,omitempty"` MergeSources []uuid.UUID `json:"merge_sources,omitempty"` } func (e *Edit) GetData() *EditData { data := EditData{} err := json.Unmarshal(e.Data, &data) if err != nil { return nil } return &data } func (e *Edit) GetTagData() (*TagEditData, error) { data := TagEditData{} _ = json.Unmarshal(e.Data, &data) return &data, nil } func (e *Edit) GetPerformerData() (*PerformerEditData, error) { data := PerformerEditData{} _ = json.Unmarshal(e.Data, &data) return &data, nil } func (e *Edit) GetStudioData() (*StudioEditData, error) { data := StudioEditData{} _ = json.Unmarshal(e.Data, &data) return &data, nil } func (e *Edit) GetSceneData() (*SceneEditData, error) { data := SceneEditData{} _ = json.Unmarshal(e.Data, &data) return &data, nil } func (e *Edit) IsDestructive() bool { if e.Operation == OperationEnumDestroy.String() || e.Operation == OperationEnumMerge.String() { return true } // When renaming a performer and not updating the performance aliases if (e.Operation == OperationEnumModify.String() || e.Operation == OperationEnumMerge.String()) && e.TargetType == TargetTypeEnumPerformer.String() { data, _ := e.GetPerformerData() if data.New.Name != nil { oldName := "" if data.Old.Name != nil { oldName = strings.TrimSpace(*data.Old.Name) } return oldName != *data.New.Name && !data.SetModifyAliases } } return false } type TagEdit struct { EditID uuid.UUID `json:"-"` Name *string `json:"name,omitempty"` Description *string `json:"description,omitempty"` AddedAliases []string `json:"added_aliases,omitempty"` RemovedAliases []string `json:"removed_aliases,omitempty"` CategoryID *uuid.UUID `json:"category_id,omitempty"` } func (TagEdit) IsEditDetails() {} type TagEditData struct { New *TagEdit `json:"new_data,omitempty"` Old *TagEdit `json:"old_data,omitempty"` MergeSources []uuid.UUID `json:"merge_sources,omitempty"` } type PerformerEdit struct { EditID uuid.UUID `json:"-"` Name *string `json:"name,omitempty"` Disambiguation *string `json:"disambiguation,omitempty"` AddedAliases []string `json:"added_aliases,omitempty"` RemovedAliases []string `json:"removed_aliases,omitempty"` Gender *string `json:"gender,omitempty"` AddedUrls []URL `json:"added_urls,omitempty"` RemovedUrls []URL `json:"removed_urls,omitempty"` Birthdate *string `json:"birthdate,omitempty"` Deathdate *string `json:"deathdate,omitempty"` Ethnicity *string `json:"ethnicity,omitempty"` Country *string `json:"country,omitempty"` EyeColor *string `json:"eye_color,omitempty"` HairColor *string `json:"hair_color,omitempty"` Height *int `json:"height,omitempty"` CupSize *string `json:"cup_size,omitempty"` BandSize *int `json:"band_size,omitempty"` WaistSize *int `json:"waist_size,omitempty"` HipSize *int `json:"hip_size,omitempty"` BreastType *string `json:"breast_type,omitempty"` CareerStartYear *int `json:"career_start_year,omitempty"` CareerEndYear *int `json:"career_end_year,omitempty"` AddedTattoos []BodyModification `json:"added_tattoos,omitempty"` RemovedTattoos []BodyModification `json:"removed_tattoos,omitempty"` AddedPiercings []BodyModification `json:"added_piercings,omitempty"` RemovedPiercings []BodyModification `json:"removed_piercings,omitempty"` AddedImages []uuid.UUID `json:"added_images,omitempty"` RemovedImages []uuid.UUID `json:"removed_images,omitempty"` DraftID *uuid.UUID `json:"draft_id,omitempty"` } func (PerformerEdit) IsEditDetails() {} type PerformerEditData struct { New *PerformerEdit `json:"new_data,omitempty"` Old *PerformerEdit `json:"old_data,omitempty"` MergeSources []uuid.UUID `json:"merge_sources,omitempty"` SetModifyAliases bool `json:"modify_aliases,omitempty"` SetMergeAliases bool `json:"merge_aliases,omitempty"` } type StudioEdit struct { EditID uuid.UUID `json:"-"` Name *string `json:"name"` // Added and modified URLs AddedUrls []URL `json:"added_urls,omitempty"` RemovedUrls []URL `json:"removed_urls,omitempty"` ParentID *uuid.UUID `json:"parent_id,omitempty"` AddedImages []uuid.UUID `json:"added_images,omitempty"` RemovedImages []uuid.UUID `json:"removed_images,omitempty"` AddedAliases []string `json:"added_aliases,omitempty"` RemovedAliases []string `json:"removed_aliases,omitempty"` } func (StudioEdit) IsEditDetails() {} type StudioEditData struct { New *StudioEdit `json:"new_data,omitempty"` Old *StudioEdit `json:"old_data,omitempty"` MergeSources []uuid.UUID `json:"merge_sources,omitempty"` } type SceneEdit struct { EditID uuid.UUID `json:"-"` Title *string `json:"title,omitempty"` Details *string `json:"details,omitempty"` AddedUrls []URL `json:"added_urls,omitempty"` RemovedUrls []URL `json:"removed_urls,omitempty"` Date *string `json:"date,omitempty"` ProductionDate *string `json:"production_date,omitempty"` StudioID *uuid.UUID `json:"studio_id,omitempty"` AddedPerformers []PerformerAppearanceInput `json:"added_performers,omitempty"` RemovedPerformers []PerformerAppearanceInput `json:"removed_performers,omitempty"` AddedTags []uuid.UUID `json:"added_tags,omitempty"` RemovedTags []uuid.UUID `json:"removed_tags,omitempty"` AddedImages []uuid.UUID `json:"added_images,omitempty"` RemovedImages []uuid.UUID `json:"removed_images,omitempty"` AddedFingerprints []FingerprintInput `json:"added_fingerprints,omitempty"` RemovedFingerprints []FingerprintInput `json:"removed_fingerprints,omitempty"` Duration *int `json:"duration,omitempty"` Director *string `json:"director,omitempty"` Code *string `json:"code,omitempty"` DraftID *uuid.UUID `json:"draft_id,omitempty"` } func (SceneEdit) IsEditDetails() {} type SceneEditData struct { New *SceneEdit `json:"new_data,omitempty"` Old *SceneEdit `json:"old_data,omitempty"` MergeSources []uuid.UUID `json:"merge_sources,omitempty"` } type EditQuery struct { Filter EditQueryInput } ================================================ FILE: internal/models/model_image.go ================================================ package models import ( "github.com/gofrs/uuid" ) type Image struct { ID uuid.UUID `json:"id"` RemoteURL *string `json:"url"` Checksum string `json:"checksum"` Width int `json:"width"` Height int `json:"height"` } ================================================ FILE: internal/models/model_invite_key.go ================================================ package models import ( "fmt" "time" "github.com/gofrs/uuid" ) type InviteKey struct { ID uuid.UUID `json:"id"` Uses *int `json:"uses"` GeneratedBy uuid.UUID `json:"generated_by"` GeneratedAt time.Time `json:"generated_at"` Expires *time.Time `json:"expires"` } func (p InviteKey) String() string { uses := "unlimited" expires := "never" if p.Uses != nil { uses = fmt.Sprintf("%d", *p.Uses) } if p.Expires != nil { expires = p.Expires.Format(time.RFC3339) } return fmt.Sprintf("%s: [%s] expires %s", p.ID, uses, expires) } ================================================ FILE: internal/models/model_mod_audit.go ================================================ package models import ( "encoding/json" "time" "github.com/gofrs/uuid" ) type ModAudit struct { ID uuid.UUID `json:"id"` Action string `json:"action"` UserID uuid.NullUUID `json:"user_id"` TargetID uuid.UUID `json:"target_id"` TargetType string `json:"target_type"` Data string `json:"data"` Reason *string `json:"reason,omitempty"` CreatedAt time.Time `json:"created_at"` } type ModAuditQuery struct { Filter ModAuditQueryInput } type EditAmendmentAuditData struct { EditID uuid.UUID `json:"edit_id"` AmendedBy uuid.UUID `json:"amended_by"` AmendedAt time.Time `json:"amended_at"` RemovedData json.RawMessage `json:"removed_data"` } ================================================ FILE: internal/models/model_notification.go ================================================ package models import ( "time" "github.com/gofrs/uuid" ) type Notification struct { UserID uuid.UUID `json:"user_id"` Type NotificationEnum `json:"type"` TargetID uuid.UUID `json:"id"` CreatedAt time.Time `json:"created_at"` ReadAt *time.Time `json:"read_at"` } type QueryNotificationsResult struct { Input QueryNotificationsInput } var defaultSubscriptions = []NotificationEnum{ NotificationEnumCommentOwnEdit, NotificationEnumDownvoteOwnEdit, NotificationEnumFailedOwnEdit, NotificationEnumCommentCommentedEdit, NotificationEnumCommentVotedEdit, NotificationEnumUpdatedEdit, } func GetDefaultNotificationSubscriptions() []NotificationEnum { return defaultSubscriptions } ================================================ FILE: internal/models/model_performer.go ================================================ package models import ( "time" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models/assign" "github.com/stashapp/stash-box/internal/models/validator" ) type Performer struct { ID uuid.UUID `json:"id"` Name string `json:"name"` Disambiguation *string `json:"disambiguation,omitempty"` Gender *GenderEnum `json:"gender,omitempty"` BirthDate *string `json:"birth_date,omitempty"` DeathDate *string `json:"death_date,omitempty"` Ethnicity *EthnicityEnum `json:"ethnicity,omitempty"` Country *string `json:"country,omitempty"` EyeColor *EyeColorEnum `json:"eye_color,omitempty"` HairColor *HairColorEnum `json:"hair_color,omitempty"` Height *int `json:"height,omitempty"` CupSize *string `json:"cup_size,omitempty"` BandSize *int `json:"band_size,omitempty"` WaistSize *int `json:"waist_size,omitempty"` HipSize *int `json:"hip_size,omitempty"` BreastType *BreastTypeEnum `json:"breast_type,omitempty"` CareerStartYear *int `json:"career_start_year,omitempty"` CareerEndYear *int `json:"career_end_year,omitempty"` Deleted bool `json:"deleted"` Created time.Time `json:"created"` Updated time.Time `json:"updated"` } func (Performer) IsSceneDraftPerformer() {} func (p *Performer) IsEditTarget() {} type PerformerQuery struct { Filter PerformerQueryInput SearchResults *PerformerSearchResults } type GenderFacet struct { Gender GenderEnum Count int } type PerformerSearchFacets struct { Genders []GenderFacet } type PerformerSearchResults struct { Performers []Performer Count int Facets *PerformerSearchFacets } type QueryExistingPerformerResult struct { Input QueryExistingPerformerInput } func (p Performer) IsDeleted() bool { return p.Deleted } func (p *Performer) CopyFromPerformerEdit(input PerformerEdit, old PerformerEdit) { assign.String(&p.Name, input.Name) assign.StringPtr(&p.Disambiguation, input.Disambiguation, old.Disambiguation) assign.EnumPtr(&p.Gender, input.Gender, old.Gender) assign.EnumPtr(&p.Ethnicity, input.Ethnicity, old.Ethnicity) assign.StringPtr(&p.Country, input.Country, old.Country) assign.EnumPtr(&p.EyeColor, input.EyeColor, old.EyeColor) assign.EnumPtr(&p.HairColor, input.HairColor, old.HairColor) assign.IntPtr(&p.Height, input.Height, old.Height) assign.EnumPtr(&p.BreastType, input.BreastType, old.BreastType) assign.IntPtr(&p.CareerStartYear, input.CareerStartYear, old.CareerStartYear) assign.IntPtr(&p.CareerEndYear, input.CareerEndYear, old.CareerEndYear) assign.StringPtr(&p.CupSize, input.CupSize, old.CupSize) assign.IntPtr(&p.BandSize, input.BandSize, old.BandSize) assign.IntPtr(&p.HipSize, input.HipSize, old.HipSize) assign.IntPtr(&p.WaistSize, input.WaistSize, old.WaistSize) assign.StringPtr(&p.BirthDate, input.Birthdate, old.Birthdate) assign.StringPtr(&p.DeathDate, input.Deathdate, old.Deathdate) } func (p *Performer) ValidateModifyEdit(edit PerformerEditData) error { if err := validator.String("name", edit.Old.Name, p.Name); err != nil { return err } if err := validator.StringPtr("disambiguation", edit.Old.Disambiguation, p.Disambiguation); err != nil { return err } if err := validator.EnumPtr("gender", edit.Old.Gender, p.Gender); err != nil { return err } if err := validator.EnumPtr("ethnicity", edit.Old.Ethnicity, p.Ethnicity); err != nil { return err } if err := validator.StringPtr("country", edit.Old.Country, p.Country); err != nil { return err } if err := validator.EnumPtr("eye color", edit.Old.EyeColor, p.EyeColor); err != nil { return err } if err := validator.EnumPtr("hair color", edit.Old.HairColor, p.HairColor); err != nil { return err } if err := validator.IntPtr("height", edit.Old.Height, p.Height); err != nil { return err } if err := validator.EnumPtr("breast type", edit.Old.BreastType, p.BreastType); err != nil { return err } if err := validator.IntPtr("career start year", edit.Old.CareerStartYear, p.CareerStartYear); err != nil { return err } if err := validator.IntPtr("career end year", edit.Old.CareerEndYear, p.CareerEndYear); err != nil { return err } if err := validator.StringPtr("cup size", edit.Old.CupSize, p.CupSize); err != nil { return err } if err := validator.IntPtr("band size", edit.Old.BandSize, p.BandSize); err != nil { return err } if err := validator.IntPtr("hip size", edit.Old.HipSize, p.HipSize); err != nil { return err } if err := validator.IntPtr("waist size", edit.Old.WaistSize, p.WaistSize); err != nil { return err } if err := validator.StringPtr("birthdate", edit.Old.Birthdate, p.BirthDate); err != nil { return err } return validator.StringPtr("deathdate", edit.Old.Deathdate, p.DeathDate) } ================================================ FILE: internal/models/model_scene.go ================================================ package models import ( "time" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models/assign" "github.com/stashapp/stash-box/internal/models/validator" ) type Scene struct { ID uuid.UUID `json:"id"` Title *string `json:"title"` Details *string `json:"details"` Date *string `json:"date"` ProductionDate *string `json:"production_date"` StudioID uuid.NullUUID `json:"studio_id"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` Duration *int `json:"duration"` Director *string `json:"director"` Code *string `json:"code"` Deleted bool `json:"deleted"` } func (s *Scene) IsEditTarget() {} type SceneFingerprint struct { SceneID uuid.UUID `json:"scene_id"` UserID uuid.UUID `json:"user_id"` Hash FingerprintHash `json:"hash"` Algorithm string `json:"algorithm"` Duration int `json:"duration"` CreatedAt time.Time `json:"created_at"` Vote int `json:"vote"` } type SceneQuery struct { Filter SceneQueryInput SearchResults *SceneSearchResults } type SceneSearchResults struct { Scenes []Scene Count int } type QueryExistingSceneResult struct { Input QueryExistingSceneInput } func (s Scene) IsDeleted() bool { return s.Deleted } func (s *Scene) CopyFromSceneEdit(input SceneEdit, old *SceneEdit) { assign.StringPtr(&s.Title, input.Title, old.Title) assign.StringPtr(&s.Details, input.Details, old.Details) assign.NullUUID(&s.StudioID, input.StudioID, old.StudioID) assign.IntPtr(&s.Duration, input.Duration, old.Duration) assign.StringPtr(&s.Director, input.Director, old.Director) assign.StringPtr(&s.Code, input.Code, old.Code) assign.StringPtr(&s.Date, input.Date, old.Date) assign.StringPtr(&s.ProductionDate, input.ProductionDate, old.ProductionDate) } func (s *Scene) ValidateModifyEdit(edit SceneEditData) error { if err := validator.StringPtr("Title", edit.Old.Title, s.Title); err != nil { return err } if err := validator.StringPtr("Details", edit.Old.Details, s.Details); err != nil { return err } if err := validator.StringPtr("Date", edit.Old.Date, s.Date); err != nil { return err } if err := validator.StringPtr("ProductionDate", edit.Old.ProductionDate, s.ProductionDate); err != nil { return err } if err := validator.UUID("StudioID", edit.Old.StudioID, s.StudioID); err != nil { return err } if err := validator.IntPtr("Duration", edit.Old.Duration, s.Duration); err != nil { return err } if err := validator.StringPtr("Director", edit.Old.Director, s.Director); err != nil { return err } return validator.StringPtr("Code", edit.Old.Code, s.Code) } type PerformerScene struct { PerformerID uuid.UUID As *string SceneID uuid.UUID } ================================================ FILE: internal/models/model_site.go ================================================ package models import ( "time" "github.com/gofrs/uuid" ) type Site struct { ID uuid.UUID `json:"id"` Name string `json:"name"` Description *string `json:"description"` URL *string `json:"url"` Regex *string `json:"regex"` ValidTypes []string `json:"valid_types"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } ================================================ FILE: internal/models/model_studio.go ================================================ package models import ( "time" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models/assign" "github.com/stashapp/stash-box/internal/models/validator" ) type Studio struct { ID uuid.UUID `json:"id"` Name string `json:"name"` ParentStudioID uuid.NullUUID `json:"parent_studio_id"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` Deleted bool `json:"deleted"` } func (Studio) IsSceneDraftStudio() {} func (s *Studio) IsEditTarget() {} func (s Studio) IsDeleted() bool { return s.Deleted } func (s *Studio) CopyFromStudioEdit(input StudioEdit, existing *StudioEdit) { assign.String(&s.Name, input.Name) assign.NullUUID(&s.ParentStudioID, input.ParentID, existing.ParentID) } func (s *Studio) ValidateModifyEdit(edit StudioEditData) error { if err := validator.String("name", edit.Old.Name, s.Name); err != nil { return err } return validator.UUID("ParentID", edit.Old.ParentID, s.ParentStudioID) } ================================================ FILE: internal/models/model_tag.go ================================================ package models import ( "time" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models/assign" "github.com/stashapp/stash-box/internal/models/validator" ) type Tag struct { ID uuid.UUID `json:"id"` Name string `json:"name"` Description *string `json:"description,omitempty"` Deleted bool `json:"deleted"` CategoryID uuid.NullUUID Created time.Time `json:"created"` Updated time.Time `json:"updated"` } func (Tag) IsSceneDraftTag() {} func (t *Tag) IsEditTarget() {} func (t Tag) IsDeleted() bool { return t.Deleted } func (t *Tag) CopyFromTagEdit(input TagEdit, existing *TagEdit) { assign.String(&t.Name, input.Name) assign.StringPtr(&t.Description, input.Description, existing.Description) assign.NullUUID(&t.CategoryID, input.CategoryID, existing.CategoryID) } func (t *Tag) ValidateModifyEdit(edit TagEditData) error { if err := validator.String("name", edit.Old.Name, t.Name); err != nil { return err } if err := validator.StringPtr("description", edit.Old.Description, t.Description); err != nil { return err } return validator.UUID("CategoryID", edit.Old.CategoryID, t.CategoryID) } ================================================ FILE: internal/models/model_tag_category.go ================================================ package models import ( "time" "github.com/gofrs/uuid" ) type TagCategory struct { ID uuid.UUID `json:"id"` Name string `json:"name"` Group string `json:"group"` Description *string `json:"description"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } ================================================ FILE: internal/models/model_user.go ================================================ package models import ( "time" "github.com/gofrs/uuid" "golang.org/x/crypto/bcrypt" ) type User struct { ID uuid.UUID `json:"id"` Name string `json:"name"` PasswordHash string `json:"password_hash"` Email string `json:"email"` APIKey string `json:"api_key"` APICalls int `json:"api_calls"` InviteTokens int `json:"invite_tokens"` InvitedByID uuid.NullUUID `json:"invited_by"` LastAPICall time.Time `json:"last_api_call"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } func (p *User) SetPasswordHash(pw string) error { // generate password from input hash, err := bcrypt.GenerateFromPassword([]byte(pw), bcrypt.DefaultCost) if err != nil { return err } p.PasswordHash = string(hash) return nil } func (p User) IsPasswordCorrect(pw string) bool { err := bcrypt.CompareHashAndPassword([]byte(p.PasswordHash), []byte(pw)) return err == nil } ================================================ FILE: internal/models/model_user_tokens.go ================================================ package models import ( "encoding/json" "time" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/pkg/utils" ) const ( UserTokenTypeNewUser = "NEW_USER" UserTokenTypeResetPassword = "RESET_PASSWORD" UserTokenTypeConfirmOldEmail = "CONFIRM_OLD_EMAIL" UserTokenTypeConfirmNewEmail = "CONFIRM_NEW_EMAIL" ) type UserToken struct { ID uuid.UUID `json:"id"` Data json.RawMessage `json:"data"` Type string `json:"type"` CreatedAt time.Time `json:"created_at"` ExpiresAt time.Time `json:"expires_at"` } func (t *UserToken) SetData(data interface{}) error { jsonData, err := utils.ToJSON(data) if err != nil { return err } t.Data = jsonData return nil } type NewUserTokenData struct { Email string `json:"email"` InviteKey *uuid.UUID `json:"invite_key,omitempty"` } func (t *UserToken) GetNewUserTokenData() (*NewUserTokenData, error) { var obj NewUserTokenData err := utils.FromJSON(t.Data, &obj) return &obj, err } type UserTokenData struct { UserID uuid.UUID `json:"user_id"` } func (t *UserToken) GetUserTokenData() (*UserTokenData, error) { var obj UserTokenData err := utils.FromJSON(t.Data, &obj) return &obj, err } type ChangeEmailTokenData struct { UserID uuid.UUID `json:"user_id"` Email string `json:"email"` } func (t *UserToken) GetChangeEmailTokenData() (*ChangeEmailTokenData, error) { var obj ChangeEmailTokenData err := utils.FromJSON(t.Data, &obj) return &obj, err } ================================================ FILE: internal/models/scalars.go ================================================ package models import ( "fmt" "io" "strconv" "strings" "github.com/99designs/gqlgen/graphql" "github.com/gofrs/uuid" ) type ID uuid.UUID // Creates a marshaller which converts a uuid to a string func MarshalID(id uuid.UUID) graphql.Marshaler { return graphql.WriterFunc(func(w io.Writer) { _, e := io.WriteString(w, fmt.Sprintf("%s%s%s", "\"", id.String(), "\"")) if e != nil { panic(e) } }) } // Unmarshalls a string to a uuid func UnmarshalID(v any) (uuid.UUID, error) { str, ok := v.(string) if !ok { return uuid.UUID{}, fmt.Errorf("ids must be strings") } withoutQuotes := strings.ReplaceAll(str, "\"", "") i, err := uuid.FromString(withoutQuotes) return i, err } // FingerprintHash stores fingerprint hashes as int64 internally // but serializes as hex string type FingerprintHash int64 func (h FingerprintHash) Int64() int64 { return int64(h) } // Hex returns the hash as a 16-character zero-padded hex string func (h FingerprintHash) Hex() string { return fmt.Sprintf("%016x", uint64(h)) } // MarshalJSON serializes as hex string for JSONB storage compatibility func (h FingerprintHash) MarshalJSON() ([]byte, error) { return fmt.Appendf(nil, "\"%016x\"", uint64(h)), nil } // UnmarshalJSON deserializes from hex string func (h *FingerprintHash) UnmarshalJSON(data []byte) error { str := strings.Trim(string(data), "\"") hashUint, err := strconv.ParseUint(str, 16, 64) if err != nil { return fmt.Errorf("invalid fingerprint hash: %w", err) } *h = FingerprintHash(int64(hashUint)) return nil } // MarshalFingerprintHash converts int64 to hex string for GraphQL output func MarshalFingerprintHash(h FingerprintHash) graphql.Marshaler { return graphql.WriterFunc(func(w io.Writer) { _, e := io.WriteString(w, fmt.Sprintf("\"%016x\"", uint64(h))) if e != nil { panic(e) } }) } // UnmarshalFingerprintHash converts hex string from clients to int64. // Returns 0 for oversized hashes (e.g. MD5) func UnmarshalFingerprintHash(v any) (FingerprintHash, error) { str, ok := v.(string) if !ok { return 0, fmt.Errorf("fingerprint hash must be a string") } withoutQuotes := strings.ReplaceAll(str, "\"", "") // Return 0 for hashes that don't fit in 64 bits (e.g. MD5 is 128 bits) if len(withoutQuotes) > 16 { return 0, nil } hashUint, err := strconv.ParseUint(withoutQuotes, 16, 64) if err != nil { return 0, fmt.Errorf("invalid fingerprint hash: %w", err) } return FingerprintHash(int64(hashUint)), nil } ================================================ FILE: internal/models/translate.go ================================================ package models import ( "fmt" "reflect" "regexp" "time" "github.com/gofrs/uuid" ) // editDiff translates edit details input fields into edit data type editDiff struct { } type stringEnum interface { IsValid() bool String() string } func (d *editDiff) string(oldVal *string, newVal *string) (oldOut *string, newOut *string) { if oldVal != nil && (newVal == nil || *newVal != *oldVal) { value := *oldVal oldOut = &value } if newVal != nil && (oldVal == nil || *newVal != *oldVal) { value := *newVal newOut = &value } return } func (d *editDiff) int(oldVal *int, newVal *int) (oldOut *int, newOut *int) { if oldVal != nil && (newVal == nil || *newVal != *oldVal) { oldOut = oldVal } if newVal != nil && (oldVal == nil || *newVal != *oldVal) { newOut = newVal } return } func (d *editDiff) nullUUID(oldVal uuid.NullUUID, newVal *uuid.UUID) (oldOut *uuid.UUID, newOut *uuid.UUID) { if oldVal.Valid && (newVal == nil || *newVal != oldVal.UUID) { oldOut = &oldVal.UUID } if newVal != nil && (!oldVal.Valid || *newVal != oldVal.UUID) { newOut = newVal } return } func (d *editDiff) enum(oldVal stringEnum, newVal stringEnum) (oldOut *string, newOut *string) { oldNil := reflect.ValueOf(oldVal).IsNil() newNil := reflect.ValueOf(newVal).IsNil() if !oldNil && oldVal.IsValid() && (newNil || !newVal.IsValid() || newVal.String() != oldVal.String()) { value := oldVal.String() oldOut = &value } if !newNil && newVal.IsValid() && (oldNil || !oldVal.IsValid() || newVal.String() != oldVal.String()) { value := newVal.String() newOut = &value } return } var ErrInvalidDate = fmt.Errorf("invalid fuzzy date") var dateValidator = regexp.MustCompile(`^\d{4}(-\d{2}){0,2}$`) func ValidateFuzzyString(date *string) error { if date == nil { return nil } if !dateValidator.MatchString(*date) { return ErrInvalidDate } fuzzyDate := *date if len(fuzzyDate) == 4 { fuzzyDate += "-01-01" } else if len(fuzzyDate) == 7 { fuzzyDate += "-01" } _, err := time.Parse("2006-01-02", fuzzyDate) if err != nil { return ErrInvalidDate } return nil } ================================================ FILE: internal/models/url.go ================================================ package models import "github.com/gofrs/uuid" type URL struct { URL string `json:"url"` SiteID uuid.UUID `json:"site_id"` } ================================================ FILE: internal/models/validator/validator.go ================================================ package validator import ( "fmt" "reflect" "github.com/gofrs/uuid" ) type StringEnum interface { IsValid() bool String() string } type ErrEditPrerequisiteFailed struct { field string expected interface{} actual interface{} } func (e *ErrEditPrerequisiteFailed) Error() string { expected := "_blank_" if e.expected != "" { expected = fmt.Sprintf("**%v**", e.expected) } actual := "_blank_" if e.actual != "" { actual = fmt.Sprintf("**%v**", e.actual) } return fmt.Sprintf("Expected %s to be %s, but was %s.", e.field, expected, actual) } func newError(field string, expected interface{}, actual interface{}) error { return &ErrEditPrerequisiteFailed{field, expected, actual} } // String validates string fields func String(field string, old *string, current string) error { if old != nil && *old != current { return newError(field, *old, current) } return nil } // StringPtr validates string pointer fields func StringPtr(field string, old *string, current *string) error { if old != nil && current != nil { if *old != *current { return newError(field, *old, *current) } } return nil } // IntPtr validates int pointer fields func IntPtr(field string, old *int, current *int) error { if old != nil && current != nil { if *old != *current { return newError(field, *old, current) } } return nil } // UUID validates UUID fields func UUID(field string, old *uuid.UUID, current uuid.NullUUID) error { if old != nil && (!current.Valid || (*old != current.UUID)) { currentUUID := "" if current.Valid { currentUUID = current.UUID.String() } return newError(field, old.String(), currentUUID) } return nil } // EnumPtr validates enum pointer fields using generics func EnumPtr[T StringEnum](field string, old *string, current *T) error { if old != nil && current != nil { currentVal := reflect.ValueOf(current) if !currentVal.IsNil() { currentEnum := currentVal.Elem().Interface().(T) if currentEnum.IsValid() && *old != currentEnum.String() { return newError(field, *old, currentEnum.String()) } } } return nil } ================================================ FILE: internal/queries/copyfrom.go ================================================ // Code generated by sqlc. DO NOT EDIT. // versions: // sqlc v1.29.0 // source: copyfrom.go package queries import ( "context" ) // iteratorForCreatePerformerAliases implements pgx.CopyFromSource. type iteratorForCreatePerformerAliases struct { rows []CreatePerformerAliasesParams skippedFirstNextCall bool } func (r *iteratorForCreatePerformerAliases) Next() bool { if len(r.rows) == 0 { return false } if !r.skippedFirstNextCall { r.skippedFirstNextCall = true return true } r.rows = r.rows[1:] return len(r.rows) > 0 } func (r iteratorForCreatePerformerAliases) Values() ([]interface{}, error) { return []interface{}{ r.rows[0].PerformerID, r.rows[0].Alias, }, nil } func (r iteratorForCreatePerformerAliases) Err() error { return nil } func (q *Queries) CreatePerformerAliases(ctx context.Context, arg []CreatePerformerAliasesParams) (int64, error) { return q.db.CopyFrom(ctx, []string{"performer_aliases"}, []string{"performer_id", "alias"}, &iteratorForCreatePerformerAliases{rows: arg}) } // iteratorForCreatePerformerImages implements pgx.CopyFromSource. type iteratorForCreatePerformerImages struct { rows []CreatePerformerImagesParams skippedFirstNextCall bool } func (r *iteratorForCreatePerformerImages) Next() bool { if len(r.rows) == 0 { return false } if !r.skippedFirstNextCall { r.skippedFirstNextCall = true return true } r.rows = r.rows[1:] return len(r.rows) > 0 } func (r iteratorForCreatePerformerImages) Values() ([]interface{}, error) { return []interface{}{ r.rows[0].PerformerID, r.rows[0].ImageID, }, nil } func (r iteratorForCreatePerformerImages) Err() error { return nil } func (q *Queries) CreatePerformerImages(ctx context.Context, arg []CreatePerformerImagesParams) (int64, error) { return q.db.CopyFrom(ctx, []string{"performer_images"}, []string{"performer_id", "image_id"}, &iteratorForCreatePerformerImages{rows: arg}) } // iteratorForCreatePerformerPiercings implements pgx.CopyFromSource. type iteratorForCreatePerformerPiercings struct { rows []CreatePerformerPiercingsParams skippedFirstNextCall bool } func (r *iteratorForCreatePerformerPiercings) Next() bool { if len(r.rows) == 0 { return false } if !r.skippedFirstNextCall { r.skippedFirstNextCall = true return true } r.rows = r.rows[1:] return len(r.rows) > 0 } func (r iteratorForCreatePerformerPiercings) Values() ([]interface{}, error) { return []interface{}{ r.rows[0].PerformerID, r.rows[0].Location, r.rows[0].Description, }, nil } func (r iteratorForCreatePerformerPiercings) Err() error { return nil } func (q *Queries) CreatePerformerPiercings(ctx context.Context, arg []CreatePerformerPiercingsParams) (int64, error) { return q.db.CopyFrom(ctx, []string{"performer_piercings"}, []string{"performer_id", "location", "description"}, &iteratorForCreatePerformerPiercings{rows: arg}) } // iteratorForCreatePerformerTattoos implements pgx.CopyFromSource. type iteratorForCreatePerformerTattoos struct { rows []CreatePerformerTattoosParams skippedFirstNextCall bool } func (r *iteratorForCreatePerformerTattoos) Next() bool { if len(r.rows) == 0 { return false } if !r.skippedFirstNextCall { r.skippedFirstNextCall = true return true } r.rows = r.rows[1:] return len(r.rows) > 0 } func (r iteratorForCreatePerformerTattoos) Values() ([]interface{}, error) { return []interface{}{ r.rows[0].PerformerID, r.rows[0].Location, r.rows[0].Description, }, nil } func (r iteratorForCreatePerformerTattoos) Err() error { return nil } func (q *Queries) CreatePerformerTattoos(ctx context.Context, arg []CreatePerformerTattoosParams) (int64, error) { return q.db.CopyFrom(ctx, []string{"performer_tattoos"}, []string{"performer_id", "location", "description"}, &iteratorForCreatePerformerTattoos{rows: arg}) } // iteratorForCreatePerformerURLs implements pgx.CopyFromSource. type iteratorForCreatePerformerURLs struct { rows []CreatePerformerURLsParams skippedFirstNextCall bool } func (r *iteratorForCreatePerformerURLs) Next() bool { if len(r.rows) == 0 { return false } if !r.skippedFirstNextCall { r.skippedFirstNextCall = true return true } r.rows = r.rows[1:] return len(r.rows) > 0 } func (r iteratorForCreatePerformerURLs) Values() ([]interface{}, error) { return []interface{}{ r.rows[0].PerformerID, r.rows[0].Url, r.rows[0].SiteID, }, nil } func (r iteratorForCreatePerformerURLs) Err() error { return nil } func (q *Queries) CreatePerformerURLs(ctx context.Context, arg []CreatePerformerURLsParams) (int64, error) { return q.db.CopyFrom(ctx, []string{"performer_urls"}, []string{"performer_id", "url", "site_id"}, &iteratorForCreatePerformerURLs{rows: arg}) } // iteratorForCreateSceneFingerprints implements pgx.CopyFromSource. type iteratorForCreateSceneFingerprints struct { rows []CreateSceneFingerprintsParams skippedFirstNextCall bool } func (r *iteratorForCreateSceneFingerprints) Next() bool { if len(r.rows) == 0 { return false } if !r.skippedFirstNextCall { r.skippedFirstNextCall = true return true } r.rows = r.rows[1:] return len(r.rows) > 0 } func (r iteratorForCreateSceneFingerprints) Values() ([]interface{}, error) { return []interface{}{ r.rows[0].FingerprintID, r.rows[0].SceneID, r.rows[0].UserID, r.rows[0].Duration, }, nil } func (r iteratorForCreateSceneFingerprints) Err() error { return nil } func (q *Queries) CreateSceneFingerprints(ctx context.Context, arg []CreateSceneFingerprintsParams) (int64, error) { return q.db.CopyFrom(ctx, []string{"scene_fingerprints"}, []string{"fingerprint_id", "scene_id", "user_id", "duration"}, &iteratorForCreateSceneFingerprints{rows: arg}) } // iteratorForCreateSceneImages implements pgx.CopyFromSource. type iteratorForCreateSceneImages struct { rows []CreateSceneImagesParams skippedFirstNextCall bool } func (r *iteratorForCreateSceneImages) Next() bool { if len(r.rows) == 0 { return false } if !r.skippedFirstNextCall { r.skippedFirstNextCall = true return true } r.rows = r.rows[1:] return len(r.rows) > 0 } func (r iteratorForCreateSceneImages) Values() ([]interface{}, error) { return []interface{}{ r.rows[0].SceneID, r.rows[0].ImageID, }, nil } func (r iteratorForCreateSceneImages) Err() error { return nil } func (q *Queries) CreateSceneImages(ctx context.Context, arg []CreateSceneImagesParams) (int64, error) { return q.db.CopyFrom(ctx, []string{"scene_images"}, []string{"scene_id", "image_id"}, &iteratorForCreateSceneImages{rows: arg}) } // iteratorForCreateScenePerformers implements pgx.CopyFromSource. type iteratorForCreateScenePerformers struct { rows []CreateScenePerformersParams skippedFirstNextCall bool } func (r *iteratorForCreateScenePerformers) Next() bool { if len(r.rows) == 0 { return false } if !r.skippedFirstNextCall { r.skippedFirstNextCall = true return true } r.rows = r.rows[1:] return len(r.rows) > 0 } func (r iteratorForCreateScenePerformers) Values() ([]interface{}, error) { return []interface{}{ r.rows[0].SceneID, r.rows[0].PerformerID, r.rows[0].As, }, nil } func (r iteratorForCreateScenePerformers) Err() error { return nil } // Scene performers func (q *Queries) CreateScenePerformers(ctx context.Context, arg []CreateScenePerformersParams) (int64, error) { return q.db.CopyFrom(ctx, []string{"scene_performers"}, []string{"scene_id", "performer_id", "as"}, &iteratorForCreateScenePerformers{rows: arg}) } // iteratorForCreateSceneTags implements pgx.CopyFromSource. type iteratorForCreateSceneTags struct { rows []CreateSceneTagsParams skippedFirstNextCall bool } func (r *iteratorForCreateSceneTags) Next() bool { if len(r.rows) == 0 { return false } if !r.skippedFirstNextCall { r.skippedFirstNextCall = true return true } r.rows = r.rows[1:] return len(r.rows) > 0 } func (r iteratorForCreateSceneTags) Values() ([]interface{}, error) { return []interface{}{ r.rows[0].SceneID, r.rows[0].TagID, }, nil } func (r iteratorForCreateSceneTags) Err() error { return nil } // Scene tags management func (q *Queries) CreateSceneTags(ctx context.Context, arg []CreateSceneTagsParams) (int64, error) { return q.db.CopyFrom(ctx, []string{"scene_tags"}, []string{"scene_id", "tag_id"}, &iteratorForCreateSceneTags{rows: arg}) } // iteratorForCreateSceneURLs implements pgx.CopyFromSource. type iteratorForCreateSceneURLs struct { rows []CreateSceneURLsParams skippedFirstNextCall bool } func (r *iteratorForCreateSceneURLs) Next() bool { if len(r.rows) == 0 { return false } if !r.skippedFirstNextCall { r.skippedFirstNextCall = true return true } r.rows = r.rows[1:] return len(r.rows) > 0 } func (r iteratorForCreateSceneURLs) Values() ([]interface{}, error) { return []interface{}{ r.rows[0].SceneID, r.rows[0].Url, r.rows[0].SiteID, }, nil } func (r iteratorForCreateSceneURLs) Err() error { return nil } // Scene URLs func (q *Queries) CreateSceneURLs(ctx context.Context, arg []CreateSceneURLsParams) (int64, error) { return q.db.CopyFrom(ctx, []string{"scene_urls"}, []string{"scene_id", "url", "site_id"}, &iteratorForCreateSceneURLs{rows: arg}) } // iteratorForCreateStudioAliases implements pgx.CopyFromSource. type iteratorForCreateStudioAliases struct { rows []CreateStudioAliasesParams skippedFirstNextCall bool } func (r *iteratorForCreateStudioAliases) Next() bool { if len(r.rows) == 0 { return false } if !r.skippedFirstNextCall { r.skippedFirstNextCall = true return true } r.rows = r.rows[1:] return len(r.rows) > 0 } func (r iteratorForCreateStudioAliases) Values() ([]interface{}, error) { return []interface{}{ r.rows[0].StudioID, r.rows[0].Alias, }, nil } func (r iteratorForCreateStudioAliases) Err() error { return nil } // Studio aliases func (q *Queries) CreateStudioAliases(ctx context.Context, arg []CreateStudioAliasesParams) (int64, error) { return q.db.CopyFrom(ctx, []string{"studio_aliases"}, []string{"studio_id", "alias"}, &iteratorForCreateStudioAliases{rows: arg}) } // iteratorForCreateStudioImages implements pgx.CopyFromSource. type iteratorForCreateStudioImages struct { rows []CreateStudioImagesParams skippedFirstNextCall bool } func (r *iteratorForCreateStudioImages) Next() bool { if len(r.rows) == 0 { return false } if !r.skippedFirstNextCall { r.skippedFirstNextCall = true return true } r.rows = r.rows[1:] return len(r.rows) > 0 } func (r iteratorForCreateStudioImages) Values() ([]interface{}, error) { return []interface{}{ r.rows[0].StudioID, r.rows[0].ImageID, }, nil } func (r iteratorForCreateStudioImages) Err() error { return nil } // Studio images func (q *Queries) CreateStudioImages(ctx context.Context, arg []CreateStudioImagesParams) (int64, error) { return q.db.CopyFrom(ctx, []string{"studio_images"}, []string{"studio_id", "image_id"}, &iteratorForCreateStudioImages{rows: arg}) } // iteratorForCreateStudioURLs implements pgx.CopyFromSource. type iteratorForCreateStudioURLs struct { rows []CreateStudioURLsParams skippedFirstNextCall bool } func (r *iteratorForCreateStudioURLs) Next() bool { if len(r.rows) == 0 { return false } if !r.skippedFirstNextCall { r.skippedFirstNextCall = true return true } r.rows = r.rows[1:] return len(r.rows) > 0 } func (r iteratorForCreateStudioURLs) Values() ([]interface{}, error) { return []interface{}{ r.rows[0].StudioID, r.rows[0].Url, r.rows[0].SiteID, }, nil } func (r iteratorForCreateStudioURLs) Err() error { return nil } // Studio URLs func (q *Queries) CreateStudioURLs(ctx context.Context, arg []CreateStudioURLsParams) (int64, error) { return q.db.CopyFrom(ctx, []string{"studio_urls"}, []string{"studio_id", "url", "site_id"}, &iteratorForCreateStudioURLs{rows: arg}) } // iteratorForCreateTagAliases implements pgx.CopyFromSource. type iteratorForCreateTagAliases struct { rows []CreateTagAliasesParams skippedFirstNextCall bool } func (r *iteratorForCreateTagAliases) Next() bool { if len(r.rows) == 0 { return false } if !r.skippedFirstNextCall { r.skippedFirstNextCall = true return true } r.rows = r.rows[1:] return len(r.rows) > 0 } func (r iteratorForCreateTagAliases) Values() ([]interface{}, error) { return []interface{}{ r.rows[0].TagID, r.rows[0].Alias, }, nil } func (r iteratorForCreateTagAliases) Err() error { return nil } // Tag aliases func (q *Queries) CreateTagAliases(ctx context.Context, arg []CreateTagAliasesParams) (int64, error) { return q.db.CopyFrom(ctx, []string{"tag_aliases"}, []string{"tag_id", "alias"}, &iteratorForCreateTagAliases{rows: arg}) } // iteratorForCreateUserNotificationSubscriptions implements pgx.CopyFromSource. type iteratorForCreateUserNotificationSubscriptions struct { rows []CreateUserNotificationSubscriptionsParams skippedFirstNextCall bool } func (r *iteratorForCreateUserNotificationSubscriptions) Next() bool { if len(r.rows) == 0 { return false } if !r.skippedFirstNextCall { r.skippedFirstNextCall = true return true } r.rows = r.rows[1:] return len(r.rows) > 0 } func (r iteratorForCreateUserNotificationSubscriptions) Values() ([]interface{}, error) { return []interface{}{ r.rows[0].UserID, r.rows[0].Type, }, nil } func (r iteratorForCreateUserNotificationSubscriptions) Err() error { return nil } // User notification subscriptions func (q *Queries) CreateUserNotificationSubscriptions(ctx context.Context, arg []CreateUserNotificationSubscriptionsParams) (int64, error) { return q.db.CopyFrom(ctx, []string{"user_notifications"}, []string{"user_id", "type"}, &iteratorForCreateUserNotificationSubscriptions{rows: arg}) } // iteratorForCreateUserRoles implements pgx.CopyFromSource. type iteratorForCreateUserRoles struct { rows []CreateUserRolesParams skippedFirstNextCall bool } func (r *iteratorForCreateUserRoles) Next() bool { if len(r.rows) == 0 { return false } if !r.skippedFirstNextCall { r.skippedFirstNextCall = true return true } r.rows = r.rows[1:] return len(r.rows) > 0 } func (r iteratorForCreateUserRoles) Values() ([]interface{}, error) { return []interface{}{ r.rows[0].UserID, r.rows[0].Role, }, nil } func (r iteratorForCreateUserRoles) Err() error { return nil } // User roles func (q *Queries) CreateUserRoles(ctx context.Context, arg []CreateUserRolesParams) (int64, error) { return q.db.CopyFrom(ctx, []string{"user_roles"}, []string{"user_id", "role"}, &iteratorForCreateUserRoles{rows: arg}) } ================================================ FILE: internal/queries/db.go ================================================ // Code generated by sqlc. DO NOT EDIT. // versions: // sqlc v1.29.0 package queries import ( "context" "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgconn" ) type DBTX interface { Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error) Query(context.Context, string, ...interface{}) (pgx.Rows, error) QueryRow(context.Context, string, ...interface{}) pgx.Row CopyFrom(ctx context.Context, tableName pgx.Identifier, columnNames []string, rowSrc pgx.CopyFromSource) (int64, error) } func New(db DBTX) *Queries { return &Queries{db: db} } type Queries struct { db DBTX } func (q *Queries) WithTx(tx pgx.Tx) *Queries { return &Queries{ db: tx, } } ================================================ FILE: internal/queries/draft.sql.go ================================================ // Code generated by sqlc. DO NOT EDIT. // versions: // sqlc v1.29.0 // source: draft.sql package queries import ( "context" "encoding/json" "github.com/gofrs/uuid" ) const createDraft = `-- name: CreateDraft :one INSERT INTO drafts (id, user_id, type, data, created_at) VALUES ($1, $2, $3, $4, now()) RETURNING id, user_id, type, data, created_at ` type CreateDraftParams struct { ID uuid.UUID `db:"id" json:"id"` UserID uuid.UUID `db:"user_id" json:"user_id"` Type string `db:"type" json:"type"` Data json.RawMessage `db:"data" json:"data"` } // Draft queries func (q *Queries) CreateDraft(ctx context.Context, arg CreateDraftParams) (Draft, error) { row := q.db.QueryRow(ctx, createDraft, arg.ID, arg.UserID, arg.Type, arg.Data, ) var i Draft err := row.Scan( &i.ID, &i.UserID, &i.Type, &i.Data, &i.CreatedAt, ) return i, err } const deleteDraft = `-- name: DeleteDraft :exec DELETE FROM drafts WHERE id = $1 ` func (q *Queries) DeleteDraft(ctx context.Context, id uuid.UUID) error { _, err := q.db.Exec(ctx, deleteDraft, id) return err } const deleteExpiredDrafts = `-- name: DeleteExpiredDrafts :exec DELETE FROM drafts WHERE created_at <= (now()::timestamp - (INTERVAL '1 second' * $1)) ` func (q *Queries) DeleteExpiredDrafts(ctx context.Context, dollar_1 interface{}) error { _, err := q.db.Exec(ctx, deleteExpiredDrafts, dollar_1) return err } const findDraft = `-- name: FindDraft :one SELECT id, user_id, type, data, created_at FROM drafts WHERE id = $1 ` func (q *Queries) FindDraft(ctx context.Context, id uuid.UUID) (Draft, error) { row := q.db.QueryRow(ctx, findDraft, id) var i Draft err := row.Scan( &i.ID, &i.UserID, &i.Type, &i.Data, &i.CreatedAt, ) return i, err } const findDraftsByUser = `-- name: FindDraftsByUser :many SELECT id, user_id, type, data, created_at FROM drafts WHERE user_id = $1 ` func (q *Queries) FindDraftsByUser(ctx context.Context, userID uuid.UUID) ([]Draft, error) { rows, err := q.db.Query(ctx, findDraftsByUser, userID) if err != nil { return nil, err } defer rows.Close() items := []Draft{} for rows.Next() { var i Draft if err := rows.Scan( &i.ID, &i.UserID, &i.Type, &i.Data, &i.CreatedAt, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } ================================================ FILE: internal/queries/edit.sql.go ================================================ // Code generated by sqlc. DO NOT EDIT. // versions: // sqlc v1.29.0 // source: edit.sql package queries import ( "context" "time" "github.com/gofrs/uuid" ) const cancelUserEdits = `-- name: CancelUserEdits :exec UPDATE edits SET status = 'CANCELED', updated_at = NOW() WHERE user_id = $1 ` func (q *Queries) CancelUserEdits(ctx context.Context, userID uuid.NullUUID) error { _, err := q.db.Exec(ctx, cancelUserEdits, userID) return err } const createEdit = `-- name: CreateEdit :one INSERT INTO edits ( id, user_id, target_type, operation, data, votes, status, applied, bot, created_at ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, now()) RETURNING id, user_id, operation, target_type, data, votes, status, applied, created_at, updated_at, closed_at, bot, update_count ` type CreateEditParams struct { ID uuid.UUID `db:"id" json:"id"` UserID uuid.NullUUID `db:"user_id" json:"user_id"` TargetType string `db:"target_type" json:"target_type"` Operation string `db:"operation" json:"operation"` Data []byte `db:"data" json:"data"` Votes int `db:"votes" json:"votes"` Status string `db:"status" json:"status"` Applied bool `db:"applied" json:"applied"` Bot bool `db:"bot" json:"bot"` } // Edit queries func (q *Queries) CreateEdit(ctx context.Context, arg CreateEditParams) (Edit, error) { row := q.db.QueryRow(ctx, createEdit, arg.ID, arg.UserID, arg.TargetType, arg.Operation, arg.Data, arg.Votes, arg.Status, arg.Applied, arg.Bot, ) var i Edit err := row.Scan( &i.ID, &i.UserID, &i.Operation, &i.TargetType, &i.Data, &i.Votes, &i.Status, &i.Applied, &i.CreatedAt, &i.UpdatedAt, &i.ClosedAt, &i.Bot, &i.UpdateCount, ) return i, err } const createEditComment = `-- name: CreateEditComment :one INSERT INTO edit_comments (id, edit_id, user_id, text, created_at) VALUES ($1, $2, $3, $4, NOW()) RETURNING id, edit_id, user_id, created_at, text ` type CreateEditCommentParams struct { ID uuid.UUID `db:"id" json:"id"` EditID uuid.UUID `db:"edit_id" json:"edit_id"` UserID uuid.NullUUID `db:"user_id" json:"user_id"` Text string `db:"text" json:"text"` } // Edit comments func (q *Queries) CreateEditComment(ctx context.Context, arg CreateEditCommentParams) (EditComment, error) { row := q.db.QueryRow(ctx, createEditComment, arg.ID, arg.EditID, arg.UserID, arg.Text, ) var i EditComment err := row.Scan( &i.ID, &i.EditID, &i.UserID, &i.CreatedAt, &i.Text, ) return i, err } const createEditVote = `-- name: CreateEditVote :exec INSERT INTO edit_votes (edit_id, user_id, vote, created_at) VALUES ($1, $2, $3, NOW()) ON CONFLICT(edit_id, user_id) DO UPDATE SET (vote, created_at) = ($3, NOW()) ` type CreateEditVoteParams struct { EditID uuid.UUID `db:"edit_id" json:"edit_id"` UserID uuid.UUID `db:"user_id" json:"user_id"` Vote string `db:"vote" json:"vote"` } // Edit votes func (q *Queries) CreateEditVote(ctx context.Context, arg CreateEditVoteParams) error { _, err := q.db.Exec(ctx, createEditVote, arg.EditID, arg.UserID, arg.Vote) return err } const createPerformerEdit = `-- name: CreatePerformerEdit :exec INSERT INTO performer_edits (edit_id, performer_id) VALUES ($1, $2) ` type CreatePerformerEditParams struct { EditID uuid.UUID `db:"edit_id" json:"edit_id"` PerformerID uuid.UUID `db:"performer_id" json:"performer_id"` } func (q *Queries) CreatePerformerEdit(ctx context.Context, arg CreatePerformerEditParams) error { _, err := q.db.Exec(ctx, createPerformerEdit, arg.EditID, arg.PerformerID) return err } const createSceneEdit = `-- name: CreateSceneEdit :exec INSERT INTO scene_edits (edit_id, scene_id) VALUES ($1, $2) ` type CreateSceneEditParams struct { EditID uuid.UUID `db:"edit_id" json:"edit_id"` SceneID uuid.UUID `db:"scene_id" json:"scene_id"` } func (q *Queries) CreateSceneEdit(ctx context.Context, arg CreateSceneEditParams) error { _, err := q.db.Exec(ctx, createSceneEdit, arg.EditID, arg.SceneID) return err } const createStudioEdit = `-- name: CreateStudioEdit :exec INSERT INTO studio_edits (edit_id, studio_id) VALUES ($1, $2) ` type CreateStudioEditParams struct { EditID uuid.UUID `db:"edit_id" json:"edit_id"` StudioID uuid.UUID `db:"studio_id" json:"studio_id"` } func (q *Queries) CreateStudioEdit(ctx context.Context, arg CreateStudioEditParams) error { _, err := q.db.Exec(ctx, createStudioEdit, arg.EditID, arg.StudioID) return err } const createTagEdit = `-- name: CreateTagEdit :exec INSERT INTO tag_edits (edit_id, tag_id) VALUES ($1, $2) ` type CreateTagEditParams struct { EditID uuid.UUID `db:"edit_id" json:"edit_id"` TagID uuid.UUID `db:"tag_id" json:"tag_id"` } func (q *Queries) CreateTagEdit(ctx context.Context, arg CreateTagEditParams) error { _, err := q.db.Exec(ctx, createTagEdit, arg.EditID, arg.TagID) return err } const deleteEdit = `-- name: DeleteEdit :exec DELETE FROM edits WHERE id = $1 ` func (q *Queries) DeleteEdit(ctx context.Context, id uuid.UUID) error { _, err := q.db.Exec(ctx, deleteEdit, id) return err } const findCompletedEdits = `-- name: FindCompletedEdits :many SELECT id, user_id, operation, target_type, data, votes, status, applied, created_at, updated_at, closed_at, bot, update_count FROM edits WHERE status = 'PENDING' AND ( (created_at <= (now()::timestamp - (INTERVAL '1 second' * $1)) AND updated_at IS NULL) OR (updated_at <= (now()::timestamp - (INTERVAL '1 second' * $1)) AND updated_at IS NOT NULL) OR ( votes >= $2 AND ( (created_at <= (now()::timestamp - (INTERVAL '1 second' * $3)) AND updated_at IS NULL) OR (updated_at <= (now()::timestamp - (INTERVAL '1 second' * $3)) AND updated_at IS NOT NULL) ) ) ) ` type FindCompletedEditsParams struct { VotingPeriod interface{} `db:"voting_period" json:"voting_period"` MinimumVotes int `db:"minimum_votes" json:"minimum_votes"` MinimumVotingPeriod interface{} `db:"minimum_voting_period" json:"minimum_voting_period"` } // Returns pending edits that fulfill one of the criteria for being closed: // * The full voting period has passed // * The minimum voting period has passed, and the number of votes has crossed the voting threshold. // The latter only applies for destructive edits. Non-destructive edits get auto-applied when sufficient votes are cast. func (q *Queries) FindCompletedEdits(ctx context.Context, arg FindCompletedEditsParams) ([]Edit, error) { rows, err := q.db.Query(ctx, findCompletedEdits, arg.VotingPeriod, arg.MinimumVotes, arg.MinimumVotingPeriod) if err != nil { return nil, err } defer rows.Close() items := []Edit{} for rows.Next() { var i Edit if err := rows.Scan( &i.ID, &i.UserID, &i.Operation, &i.TargetType, &i.Data, &i.Votes, &i.Status, &i.Applied, &i.CreatedAt, &i.UpdatedAt, &i.ClosedAt, &i.Bot, &i.UpdateCount, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const findEdit = `-- name: FindEdit :one SELECT id, user_id, operation, target_type, data, votes, status, applied, created_at, updated_at, closed_at, bot, update_count FROM edits WHERE id = $1 ` func (q *Queries) FindEdit(ctx context.Context, id uuid.UUID) (Edit, error) { row := q.db.QueryRow(ctx, findEdit, id) var i Edit err := row.Scan( &i.ID, &i.UserID, &i.Operation, &i.TargetType, &i.Data, &i.Votes, &i.Status, &i.Applied, &i.CreatedAt, &i.UpdatedAt, &i.ClosedAt, &i.Bot, &i.UpdateCount, ) return i, err } const findPendingPerformerCreation = `-- name: FindPendingPerformerCreation :many SELECT id, user_id, operation, target_type, data, votes, status, applied, created_at, updated_at, closed_at, bot, update_count FROM edits WHERE status = 'PENDING' AND target_type = 'PERFORMER' AND ( ($1::text IS NOT NULL AND data->'new_data'->>'name' = $1) OR ($2::text[] IS NOT NULL AND jsonb_exists_any(jsonb_path_query_array(data, '$.new_data.added_urls[*].url'), $2)) ) ` type FindPendingPerformerCreationParams struct { Name *string `db:"name" json:"name"` Urls []string `db:"urls" json:"urls"` } func (q *Queries) FindPendingPerformerCreation(ctx context.Context, arg FindPendingPerformerCreationParams) ([]Edit, error) { rows, err := q.db.Query(ctx, findPendingPerformerCreation, arg.Name, arg.Urls) if err != nil { return nil, err } defer rows.Close() items := []Edit{} for rows.Next() { var i Edit if err := rows.Scan( &i.ID, &i.UserID, &i.Operation, &i.TargetType, &i.Data, &i.Votes, &i.Status, &i.Applied, &i.CreatedAt, &i.UpdatedAt, &i.ClosedAt, &i.Bot, &i.UpdateCount, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const findPendingSceneCreation = `-- name: FindPendingSceneCreation :many SELECT id, user_id, operation, target_type, data, votes, status, applied, created_at, updated_at, closed_at, bot, update_count FROM edits WHERE status = 'PENDING' AND target_type = 'SCENE' AND ( ($1::text IS NOT NULL AND $2::uuid IS NOT NULL AND data->'new_data'->>'title' = $1 AND (data->'new_data'->>'studio_id')::uuid = $2) OR ($3::text[] IS NOT NULL AND jsonb_exists_any(jsonb_path_query_array(data, '$.new_data.added_fingerprints[*].hash'), $3)) ) ` type FindPendingSceneCreationParams struct { Title *string `db:"title" json:"title"` StudioID uuid.NullUUID `db:"studio_id" json:"studio_id"` Hashes []string `db:"hashes" json:"hashes"` } func (q *Queries) FindPendingSceneCreation(ctx context.Context, arg FindPendingSceneCreationParams) ([]Edit, error) { rows, err := q.db.Query(ctx, findPendingSceneCreation, arg.Title, arg.StudioID, arg.Hashes) if err != nil { return nil, err } defer rows.Close() items := []Edit{} for rows.Next() { var i Edit if err := rows.Scan( &i.ID, &i.UserID, &i.Operation, &i.TargetType, &i.Data, &i.Votes, &i.Status, &i.Applied, &i.CreatedAt, &i.UpdatedAt, &i.ClosedAt, &i.Bot, &i.UpdateCount, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getEditComments = `-- name: GetEditComments :many SELECT id, edit_id, user_id, created_at, text FROM edit_comments WHERE edit_id = $1 ORDER BY created_at ASC ` func (q *Queries) GetEditComments(ctx context.Context, editID uuid.UUID) ([]EditComment, error) { rows, err := q.db.Query(ctx, getEditComments, editID) if err != nil { return nil, err } defer rows.Close() items := []EditComment{} for rows.Next() { var i EditComment if err := rows.Scan( &i.ID, &i.EditID, &i.UserID, &i.CreatedAt, &i.Text, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getEditCommentsByIds = `-- name: GetEditCommentsByIds :many SELECT id, edit_id, user_id, created_at, text FROM edit_comments WHERE id = ANY($1::UUID[]) ` func (q *Queries) GetEditCommentsByIds(ctx context.Context, dollar_1 []uuid.UUID) ([]EditComment, error) { rows, err := q.db.Query(ctx, getEditCommentsByIds, dollar_1) if err != nil { return nil, err } defer rows.Close() items := []EditComment{} for rows.Next() { var i EditComment if err := rows.Scan( &i.ID, &i.EditID, &i.UserID, &i.CreatedAt, &i.Text, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getEditPerformerAliases = `-- name: GetEditPerformerAliases :many WITH edit AS ( SELECT id, user_id, operation, target_type, data, votes, status, applied, created_at, updated_at, closed_at, bot, update_count FROM edits WHERE id = $1 ) ( SELECT alias FROM edit E JOIN performer_edits PE ON E.id = PE.edit_id JOIN performer_aliases PA ON PE.performer_id = PA.performer_id EXCEPT SELECT jsonb_array_elements_text(COALESCE(data->'new_data'->'removed_aliases', '[]'::jsonb)) AS alias FROM edit ) UNION SELECT jsonb_array_elements_text(COALESCE(data->'new_data'->'added_aliases', '[]'::jsonb)) AS alias FROM edit ` func (q *Queries) GetEditPerformerAliases(ctx context.Context, id uuid.UUID) ([]string, error) { rows, err := q.db.Query(ctx, getEditPerformerAliases, id) if err != nil { return nil, err } defer rows.Close() items := []string{} for rows.Next() { var alias string if err := rows.Scan(&alias); err != nil { return nil, err } items = append(items, alias) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getEditPerformerPiercings = `-- name: GetEditPerformerPiercings :many WITH edit AS ( SELECT id, user_id, operation, target_type, data, votes, status, applied, created_at, updated_at, closed_at, bot, update_count FROM edits WHERE id = $1 ), current_piercings AS ( SELECT location, description FROM edit E JOIN performer_edits PE ON E.id = PE.edit_id JOIN performer_piercings PP ON PE.performer_id = PP.performer_id ), removed_piercings AS ( SELECT elem->>'location' AS location, elem->>'description' AS description FROM edit, jsonb_array_elements(COALESCE(data->'new_data'->'removed_piercings', '[]'::jsonb)) AS elem ), added_piercings AS ( SELECT elem->>'location' AS location, elem->>'description' AS description FROM edit, jsonb_array_elements(COALESCE(data->'new_data'->'added_piercings', '[]'::jsonb)) AS elem ), final_piercings AS ( SELECT location, description FROM current_piercings EXCEPT SELECT location, description FROM removed_piercings UNION SELECT location, description FROM added_piercings ) SELECT DISTINCT location, description FROM final_piercings ` type GetEditPerformerPiercingsRow struct { Location *string `db:"location" json:"location"` Description *string `db:"description" json:"description"` } func (q *Queries) GetEditPerformerPiercings(ctx context.Context, id uuid.UUID) ([]GetEditPerformerPiercingsRow, error) { rows, err := q.db.Query(ctx, getEditPerformerPiercings, id) if err != nil { return nil, err } defer rows.Close() items := []GetEditPerformerPiercingsRow{} for rows.Next() { var i GetEditPerformerPiercingsRow if err := rows.Scan(&i.Location, &i.Description); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getEditPerformerTattoos = `-- name: GetEditPerformerTattoos :many WITH edit AS ( SELECT id, user_id, operation, target_type, data, votes, status, applied, created_at, updated_at, closed_at, bot, update_count FROM edits WHERE id = $1 ), current_tattoos AS ( SELECT location, description FROM edit E JOIN performer_edits PE ON E.id = PE.edit_id JOIN performer_tattoos PT ON PE.performer_id = PT.performer_id ), removed_tattoos AS ( SELECT elem->>'location' AS location, elem->>'description' AS description FROM edit, jsonb_array_elements(COALESCE(data->'new_data'->'removed_tattoos', '[]'::jsonb)) AS elem ), added_tattoos AS ( SELECT elem->>'location' AS location, elem->>'description' AS description FROM edit, jsonb_array_elements(COALESCE(data->'new_data'->'added_tattoos', '[]'::jsonb)) AS elem ), final_tattoos AS ( SELECT location, description FROM current_tattoos EXCEPT SELECT location, description FROM removed_tattoos UNION SELECT location, description FROM added_tattoos ) SELECT DISTINCT location, description FROM final_tattoos ` type GetEditPerformerTattoosRow struct { Location *string `db:"location" json:"location"` Description *string `db:"description" json:"description"` } func (q *Queries) GetEditPerformerTattoos(ctx context.Context, id uuid.UUID) ([]GetEditPerformerTattoosRow, error) { rows, err := q.db.Query(ctx, getEditPerformerTattoos, id) if err != nil { return nil, err } defer rows.Close() items := []GetEditPerformerTattoosRow{} for rows.Next() { var i GetEditPerformerTattoosRow if err := rows.Scan(&i.Location, &i.Description); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getEditTargetID = `-- name: GetEditTargetID :one SELECT CASE e.target_type WHEN 'SCENE' THEN se.scene_id WHEN 'PERFORMER' THEN pe.performer_id WHEN 'STUDIO' THEN ste.studio_id WHEN 'TAG' THEN te.tag_id END::UUID AS id, e.target_type FROM edits e LEFT JOIN scene_edits se ON e.id = se.edit_id LEFT JOIN performer_edits pe ON e.id = pe.edit_id LEFT JOIN studio_edits ste ON e.id = ste.edit_id LEFT JOIN tag_edits te ON e.id = te.edit_id WHERE e.id = $1 ` type GetEditTargetIDRow struct { ID uuid.UUID `db:"id" json:"id"` TargetType string `db:"target_type" json:"target_type"` } func (q *Queries) GetEditTargetID(ctx context.Context, id uuid.UUID) (GetEditTargetIDRow, error) { row := q.db.QueryRow(ctx, getEditTargetID, id) var i GetEditTargetIDRow err := row.Scan(&i.ID, &i.TargetType) return i, err } const getEditVotes = `-- name: GetEditVotes :many SELECT edit_id, user_id, created_at, vote FROM edit_votes WHERE edit_id = $1 ` func (q *Queries) GetEditVotes(ctx context.Context, editID uuid.UUID) ([]EditVote, error) { rows, err := q.db.Query(ctx, getEditVotes, editID) if err != nil { return nil, err } defer rows.Close() items := []EditVote{} for rows.Next() { var i EditVote if err := rows.Scan( &i.EditID, &i.UserID, &i.CreatedAt, &i.Vote, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getEditsByIds = `-- name: GetEditsByIds :many SELECT id, user_id, operation, target_type, data, votes, status, applied, created_at, updated_at, closed_at, bot, update_count FROM edits WHERE id = ANY($1::UUID[]) ` func (q *Queries) GetEditsByIds(ctx context.Context, dollar_1 []uuid.UUID) ([]Edit, error) { rows, err := q.db.Query(ctx, getEditsByIds, dollar_1) if err != nil { return nil, err } defer rows.Close() items := []Edit{} for rows.Next() { var i Edit if err := rows.Scan( &i.ID, &i.UserID, &i.Operation, &i.TargetType, &i.Data, &i.Votes, &i.Status, &i.Applied, &i.CreatedAt, &i.UpdatedAt, &i.ClosedAt, &i.Bot, &i.UpdateCount, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getEditsByPerformer = `-- name: GetEditsByPerformer :many SELECT e.id, e.user_id, e.operation, e.target_type, e.data, e.votes, e.status, e.applied, e.created_at, e.updated_at, e.closed_at, e.bot, e.update_count FROM edits e JOIN performer_edits pe ON e.id = pe.edit_id WHERE pe.performer_id = $1 ORDER BY e.created_at DESC ` func (q *Queries) GetEditsByPerformer(ctx context.Context, performerID uuid.UUID) ([]Edit, error) { rows, err := q.db.Query(ctx, getEditsByPerformer, performerID) if err != nil { return nil, err } defer rows.Close() items := []Edit{} for rows.Next() { var i Edit if err := rows.Scan( &i.ID, &i.UserID, &i.Operation, &i.TargetType, &i.Data, &i.Votes, &i.Status, &i.Applied, &i.CreatedAt, &i.UpdatedAt, &i.ClosedAt, &i.Bot, &i.UpdateCount, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getEditsByScene = `-- name: GetEditsByScene :many SELECT e.id, e.user_id, e.operation, e.target_type, e.data, e.votes, e.status, e.applied, e.created_at, e.updated_at, e.closed_at, e.bot, e.update_count FROM edits e JOIN scene_edits se ON e.id = se.edit_id WHERE se.scene_id = $1 ORDER BY e.created_at DESC ` func (q *Queries) GetEditsByScene(ctx context.Context, sceneID uuid.UUID) ([]Edit, error) { rows, err := q.db.Query(ctx, getEditsByScene, sceneID) if err != nil { return nil, err } defer rows.Close() items := []Edit{} for rows.Next() { var i Edit if err := rows.Scan( &i.ID, &i.UserID, &i.Operation, &i.TargetType, &i.Data, &i.Votes, &i.Status, &i.Applied, &i.CreatedAt, &i.UpdatedAt, &i.ClosedAt, &i.Bot, &i.UpdateCount, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getEditsByStudio = `-- name: GetEditsByStudio :many SELECT e.id, e.user_id, e.operation, e.target_type, e.data, e.votes, e.status, e.applied, e.created_at, e.updated_at, e.closed_at, e.bot, e.update_count FROM edits e JOIN studio_edits se ON e.id = se.edit_id WHERE se.studio_id = $1 ORDER BY e.created_at DESC ` func (q *Queries) GetEditsByStudio(ctx context.Context, studioID uuid.UUID) ([]Edit, error) { rows, err := q.db.Query(ctx, getEditsByStudio, studioID) if err != nil { return nil, err } defer rows.Close() items := []Edit{} for rows.Next() { var i Edit if err := rows.Scan( &i.ID, &i.UserID, &i.Operation, &i.TargetType, &i.Data, &i.Votes, &i.Status, &i.Applied, &i.CreatedAt, &i.UpdatedAt, &i.ClosedAt, &i.Bot, &i.UpdateCount, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getEditsByTag = `-- name: GetEditsByTag :many SELECT e.id, e.user_id, e.operation, e.target_type, e.data, e.votes, e.status, e.applied, e.created_at, e.updated_at, e.closed_at, e.bot, e.update_count FROM edits e JOIN tag_edits te ON e.id = te.edit_id WHERE te.tag_id = $1 ORDER BY e.created_at DESC ` func (q *Queries) GetEditsByTag(ctx context.Context, tagID uuid.UUID) ([]Edit, error) { rows, err := q.db.Query(ctx, getEditsByTag, tagID) if err != nil { return nil, err } defer rows.Close() items := []Edit{} for rows.Next() { var i Edit if err := rows.Scan( &i.ID, &i.UserID, &i.Operation, &i.TargetType, &i.Data, &i.Votes, &i.Status, &i.Applied, &i.CreatedAt, &i.UpdatedAt, &i.ClosedAt, &i.Bot, &i.UpdateCount, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getImagesForEdit = `-- name: GetImagesForEdit :many WITH edit AS ( SELECT id, user_id, operation, target_type, data, votes, status, applied, created_at, updated_at, closed_at, bot, update_count FROM edits WHERE edits.id = $1 ), current_images AS ( SELECT si.image_id FROM edit e JOIN scene_edits se ON e.id = se.edit_id JOIN scene_images si ON se.scene_id = si.scene_id UNION ALL SELECT pi.image_id FROM edit e JOIN performer_edits pe ON e.id = pe.edit_id JOIN performer_images pi ON pe.performer_id = pi.performer_id UNION ALL SELECT sti.image_id FROM edit e JOIN studio_edits ste ON e.id = ste.edit_id JOIN studio_images sti ON ste.studio_id = sti.studio_id ), removed_images AS ( SELECT jsonb_array_elements_text(COALESCE(data->'new_data'->'removed_images', '[]'::jsonb))::uuid AS image_id FROM edit ), added_images AS ( SELECT jsonb_array_elements_text(COALESCE(data->'new_data'->'added_images', '[]'::jsonb))::uuid AS image_id FROM edit ), final_images AS ( SELECT image_id FROM current_images WHERE image_id NOT IN (SELECT image_id FROM removed_images) UNION SELECT image_id FROM added_images ) SELECT i.id, i.url, i.width, i.height, i.checksum FROM final_images fi JOIN images i ON fi.image_id = i.id ORDER BY i.id ` // Gets current images for target entity and merges with edit's added_images/removed_images func (q *Queries) GetImagesForEdit(ctx context.Context, id uuid.UUID) ([]Image, error) { rows, err := q.db.Query(ctx, getImagesForEdit, id) if err != nil { return nil, err } defer rows.Close() items := []Image{} for rows.Next() { var i Image if err := rows.Scan( &i.ID, &i.Url, &i.Width, &i.Height, &i.Checksum, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getMergedPerformersForEdit = `-- name: GetMergedPerformersForEdit :many WITH edit AS ( SELECT id, user_id, operation, target_type, data, votes, status, applied, created_at, updated_at, closed_at, bot, update_count FROM edits WHERE edits.id = $1 ), current_performers AS ( SELECT sp.performer_id, sp."as" FROM edit e JOIN scene_edits se ON e.id = se.edit_id JOIN scene_performers sp ON se.scene_id = sp.scene_id WHERE e.target_type = 'SCENE' ), removed_performers AS ( SELECT (elem->>'performer_id')::uuid AS performer_id, elem->>'as' AS "as" FROM edit, jsonb_array_elements(COALESCE(data->'new_data'->'removed_performers', '[]'::jsonb)) AS elem ), added_performers AS ( SELECT (elem->>'performer_id')::uuid AS performer_id, elem->>'as' AS "as" FROM edit, jsonb_array_elements(COALESCE(data->'new_data'->'added_performers', '[]'::jsonb)) AS elem ), final_performers AS ( SELECT performer_id, "as" FROM current_performers EXCEPT SELECT performer_id, "as" FROM removed_performers UNION SELECT performer_id, "as" FROM added_performers ) SELECT p.id, p.name, p.disambiguation, p.gender, p.ethnicity, p.country, p.eye_color, p.hair_color, p.height, p.cup_size, p.band_size, p.hip_size, p.waist_size, p.breast_type, p.career_start_year, p.career_end_year, p.created_at, p.updated_at, p.deleted, p.birthdate, p.deathdate, fp."as" FROM final_performers fp JOIN performers p ON fp.performer_id = p.id WHERE p.deleted = FALSE ORDER BY p.name ` type GetMergedPerformersForEditRow struct { Performer Performer `db:"performer" json:"performer"` As *string `db:"as" json:"as"` } // Gets current performers for target entity and merges with edit's added_performers/removed_performers func (q *Queries) GetMergedPerformersForEdit(ctx context.Context, id uuid.UUID) ([]GetMergedPerformersForEditRow, error) { rows, err := q.db.Query(ctx, getMergedPerformersForEdit, id) if err != nil { return nil, err } defer rows.Close() items := []GetMergedPerformersForEditRow{} for rows.Next() { var i GetMergedPerformersForEditRow if err := rows.Scan( &i.Performer.ID, &i.Performer.Name, &i.Performer.Disambiguation, &i.Performer.Gender, &i.Performer.Ethnicity, &i.Performer.Country, &i.Performer.EyeColor, &i.Performer.HairColor, &i.Performer.Height, &i.Performer.CupSize, &i.Performer.BandSize, &i.Performer.HipSize, &i.Performer.WaistSize, &i.Performer.BreastType, &i.Performer.CareerStartYear, &i.Performer.CareerEndYear, &i.Performer.CreatedAt, &i.Performer.UpdatedAt, &i.Performer.Deleted, &i.Performer.Birthdate, &i.Performer.Deathdate, &i.As, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getMergedStudioAliasesForEdit = `-- name: GetMergedStudioAliasesForEdit :many WITH edit AS ( SELECT id, user_id, operation, target_type, data, votes, status, applied, created_at, updated_at, closed_at, bot, update_count FROM edits WHERE id = $1 ) ( SELECT alias FROM edit E JOIN studio_edits SE ON E.id = SE.edit_id JOIN studio_aliases SA ON SE.studio_id = SA.studio_id WHERE E.target_type = 'STUDIO' EXCEPT SELECT jsonb_array_elements_text(COALESCE(data->'new_data'->'removed_aliases', '[]'::jsonb)) AS alias FROM edit ) UNION SELECT jsonb_array_elements_text(COALESCE(data->'new_data'->'added_aliases', '[]'::jsonb)) AS alias FROM edit ` // Gets current aliases for target studio entity and merges with edit's added_aliases/removed_aliases func (q *Queries) GetMergedStudioAliasesForEdit(ctx context.Context, id uuid.UUID) ([]string, error) { rows, err := q.db.Query(ctx, getMergedStudioAliasesForEdit, id) if err != nil { return nil, err } defer rows.Close() items := []string{} for rows.Next() { var alias string if err := rows.Scan(&alias); err != nil { return nil, err } items = append(items, alias) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getMergedTagAliasesForEdit = `-- name: GetMergedTagAliasesForEdit :many WITH edit AS ( SELECT id, user_id, operation, target_type, data, votes, status, applied, created_at, updated_at, closed_at, bot, update_count FROM edits WHERE id = $1 ) ( SELECT alias FROM edit E JOIN tag_edits TE ON E.id = TE.edit_id JOIN tag_aliases TA ON TE.tag_id = TA.tag_id EXCEPT SELECT jsonb_array_elements_text(COALESCE(data->'new_data'->'removed_aliases', '[]'::jsonb)) AS alias FROM edit ) UNION SELECT jsonb_array_elements_text(COALESCE(data->'new_data'->'added_aliases', '[]'::jsonb)) AS alias FROM edit ` // Gets current aliases for target tag entity and merges with edit's added_aliases/removed_aliases func (q *Queries) GetMergedTagAliasesForEdit(ctx context.Context, id uuid.UUID) ([]string, error) { rows, err := q.db.Query(ctx, getMergedTagAliasesForEdit, id) if err != nil { return nil, err } defer rows.Close() items := []string{} for rows.Next() { var alias string if err := rows.Scan(&alias); err != nil { return nil, err } items = append(items, alias) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getMergedTagsForEdit = `-- name: GetMergedTagsForEdit :many WITH edit AS ( SELECT id, user_id, operation, target_type, data, votes, status, applied, created_at, updated_at, closed_at, bot, update_count FROM edits WHERE edits.id = $1 ), current_tags AS ( SELECT st.tag_id FROM edit e JOIN scene_edits se ON e.id = se.edit_id JOIN scene_tags st ON se.scene_id = st.scene_id WHERE e.target_type = 'SCENE' ), removed_tags AS ( SELECT jsonb_array_elements_text(COALESCE(data->'new_data'->'removed_tags', '[]'::jsonb))::uuid AS tag_id FROM edit ), added_tags AS ( SELECT jsonb_array_elements_text(COALESCE(data->'new_data'->'added_tags', '[]'::jsonb))::uuid AS tag_id FROM edit ), final_tags AS ( SELECT tag_id FROM current_tags EXCEPT SELECT tag_id FROM removed_tags UNION SELECT tag_id FROM added_tags ) SELECT t.id, t.name, t.description, t.created_at, t.updated_at, t.deleted, t.category_id FROM final_tags ft JOIN tags t ON ft.tag_id = t.id WHERE t.deleted = FALSE ORDER BY t.name ` // Gets current tags for target entity and merges with edit's added_tags/removed_tags func (q *Queries) GetMergedTagsForEdit(ctx context.Context, id uuid.UUID) ([]Tag, error) { rows, err := q.db.Query(ctx, getMergedTagsForEdit, id) if err != nil { return nil, err } defer rows.Close() items := []Tag{} for rows.Next() { var i Tag if err := rows.Scan( &i.ID, &i.Name, &i.Description, &i.CreatedAt, &i.UpdatedAt, &i.Deleted, &i.CategoryID, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getMergedURLsForEdit = `-- name: GetMergedURLsForEdit :many WITH current_urls AS ( SELECT su.url, su.site_id FROM edits e JOIN scene_edits se ON e.id = se.edit_id JOIN scene_urls su ON se.scene_id = su.scene_id WHERE e.id = $1 AND e.target_type = 'SCENE' UNION ALL SELECT pu.url, pu.site_id FROM edits e JOIN performer_edits pe ON e.id = pe.edit_id JOIN performer_urls pu ON pe.performer_id = pu.performer_id WHERE e.id = $1 AND e.target_type = 'PERFORMER' UNION ALL SELECT stu.url, stu.site_id FROM edits e JOIN studio_edits ste ON e.id = ste.edit_id JOIN studio_urls stu ON ste.studio_id = stu.studio_id WHERE e.id = $1 AND e.target_type = 'STUDIO' ), removed_urls AS ( SELECT elem->>'url' AS url, (elem->>'site_id')::uuid AS site_id FROM edits, jsonb_array_elements(COALESCE(data->'new_data'->'removed_urls', '[]'::jsonb)) AS elem WHERE id = $1 ), added_urls AS ( SELECT elem->>'url' AS url, (elem->>'site_id')::uuid AS site_id FROM edits, jsonb_array_elements(COALESCE(data->'new_data'->'added_urls', '[]'::jsonb)) AS elem WHERE id = $1 ), final_urls AS ( SELECT url, site_id FROM current_urls WHERE (url, site_id) NOT IN (SELECT url, site_id FROM removed_urls) UNION SELECT url, site_id FROM added_urls ) SELECT DISTINCT url, site_id FROM final_urls ORDER BY url ` type GetMergedURLsForEditRow struct { Url string `db:"url" json:"url"` SiteID uuid.UUID `db:"site_id" json:"site_id"` } // URL merging queries for edits // result: URL // Gets current URLs for target entity and merges with edit's added_urls/removed_urls func (q *Queries) GetMergedURLsForEdit(ctx context.Context, id uuid.UUID) ([]GetMergedURLsForEditRow, error) { rows, err := q.db.Query(ctx, getMergedURLsForEdit, id) if err != nil { return nil, err } defer rows.Close() items := []GetMergedURLsForEditRow{} for rows.Next() { var i GetMergedURLsForEditRow if err := rows.Scan(&i.Url, &i.SiteID); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const resetVotes = `-- name: ResetVotes :exec UPDATE edit_votes SET vote = 'ABSTAIN' WHERE edit_id = $1 ` func (q *Queries) ResetVotes(ctx context.Context, editID uuid.UUID) error { _, err := q.db.Exec(ctx, resetVotes, editID) return err } const updateEdit = `-- name: UpdateEdit :one UPDATE edits SET data = $2, votes = $3, status = $4, applied = $5, closed_at = $6, update_count = $7, updated_at = now() WHERE id = $1 RETURNING id, user_id, operation, target_type, data, votes, status, applied, created_at, updated_at, closed_at, bot, update_count ` type UpdateEditParams struct { ID uuid.UUID `db:"id" json:"id"` Data []byte `db:"data" json:"data"` Votes int `db:"votes" json:"votes"` Status string `db:"status" json:"status"` Applied bool `db:"applied" json:"applied"` ClosedAt *time.Time `db:"closed_at" json:"closed_at"` UpdateCount int `db:"update_count" json:"update_count"` } func (q *Queries) UpdateEdit(ctx context.Context, arg UpdateEditParams) (Edit, error) { row := q.db.QueryRow(ctx, updateEdit, arg.ID, arg.Data, arg.Votes, arg.Status, arg.Applied, arg.ClosedAt, arg.UpdateCount, ) var i Edit err := row.Scan( &i.ID, &i.UserID, &i.Operation, &i.TargetType, &i.Data, &i.Votes, &i.Status, &i.Applied, &i.CreatedAt, &i.UpdatedAt, &i.ClosedAt, &i.Bot, &i.UpdateCount, ) return i, err } const updateEditData = `-- name: UpdateEditData :one UPDATE edits SET data = $2, updated_at = now() WHERE id = $1 RETURNING id, user_id, operation, target_type, data, votes, status, applied, created_at, updated_at, closed_at, bot, update_count ` type UpdateEditDataParams struct { ID uuid.UUID `db:"id" json:"id"` Data []byte `db:"data" json:"data"` } func (q *Queries) UpdateEditData(ctx context.Context, arg UpdateEditDataParams) (Edit, error) { row := q.db.QueryRow(ctx, updateEditData, arg.ID, arg.Data) var i Edit err := row.Scan( &i.ID, &i.UserID, &i.Operation, &i.TargetType, &i.Data, &i.Votes, &i.Status, &i.Applied, &i.CreatedAt, &i.UpdatedAt, &i.ClosedAt, &i.Bot, &i.UpdateCount, ) return i, err } ================================================ FILE: internal/queries/fingerprint.sql.go ================================================ // Code generated by sqlc. DO NOT EDIT. // versions: // sqlc v1.29.0 // source: fingerprint.sql package queries import ( "context" "time" "github.com/gofrs/uuid" ) const createFingerprint = `-- name: CreateFingerprint :one INSERT INTO fingerprints (hash, algorithm) VALUES ($1, $2) ON CONFLICT (hash, algorithm) DO UPDATE SET hash = EXCLUDED.hash RETURNING id, algorithm, hash ` type CreateFingerprintParams struct { Hash int64 `db:"hash" json:"hash"` Algorithm string `db:"algorithm" json:"algorithm"` } // Fingerprint queries (normalized schema) func (q *Queries) CreateFingerprint(ctx context.Context, arg CreateFingerprintParams) (Fingerprint, error) { row := q.db.QueryRow(ctx, createFingerprint, arg.Hash, arg.Algorithm) var i Fingerprint err := row.Scan(&i.ID, &i.Algorithm, &i.Hash) return i, err } const createOrReplaceFingerprint = `-- name: CreateOrReplaceFingerprint :exec INSERT INTO scene_fingerprints (fingerprint_id, scene_id, user_id, duration, vote) VALUES ($1, $2, $3, $4, $5) ON CONFLICT ON CONSTRAINT scene_fingerprints_scene_id_fingerprint_id_user_id_key DO UPDATE SET duration = EXCLUDED.duration, vote = EXCLUDED.vote ` type CreateOrReplaceFingerprintParams struct { FingerprintID int `db:"fingerprint_id" json:"fingerprint_id"` SceneID uuid.UUID `db:"scene_id" json:"scene_id"` UserID uuid.UUID `db:"user_id" json:"user_id"` Duration int `db:"duration" json:"duration"` Vote int16 `db:"vote" json:"vote"` } func (q *Queries) CreateOrReplaceFingerprint(ctx context.Context, arg CreateOrReplaceFingerprintParams) error { _, err := q.db.Exec(ctx, createOrReplaceFingerprint, arg.FingerprintID, arg.SceneID, arg.UserID, arg.Duration, arg.Vote, ) return err } type CreateSceneFingerprintsParams struct { FingerprintID int `db:"fingerprint_id" json:"fingerprint_id"` SceneID uuid.UUID `db:"scene_id" json:"scene_id"` UserID uuid.UUID `db:"user_id" json:"user_id"` Duration int `db:"duration" json:"duration"` } const deleteAllSceneFingerprintSubmissions = `-- name: DeleteAllSceneFingerprintSubmissions :execrows DELETE FROM scene_fingerprints SFP USING fingerprints FP WHERE SFP.fingerprint_id = FP.id AND FP.hash = $1 AND FP.algorithm = $2 AND SFP.scene_id = $3 ` type DeleteAllSceneFingerprintSubmissionsParams struct { Hash int64 `db:"hash" json:"hash"` Algorithm string `db:"algorithm" json:"algorithm"` SceneID uuid.UUID `db:"scene_id" json:"scene_id"` } func (q *Queries) DeleteAllSceneFingerprintSubmissions(ctx context.Context, arg DeleteAllSceneFingerprintSubmissionsParams) (int64, error) { result, err := q.db.Exec(ctx, deleteAllSceneFingerprintSubmissions, arg.Hash, arg.Algorithm, arg.SceneID) if err != nil { return 0, err } return result.RowsAffected(), nil } const deleteSceneFingerprint = `-- name: DeleteSceneFingerprint :exec DELETE FROM scene_fingerprints SFP USING fingerprints FP WHERE SFP.fingerprint_id = FP.id AND FP.hash = $1 AND FP.algorithm = $2 AND user_id = $3 AND scene_id = $4 ` type DeleteSceneFingerprintParams struct { Hash int64 `db:"hash" json:"hash"` Algorithm string `db:"algorithm" json:"algorithm"` UserID uuid.UUID `db:"user_id" json:"user_id"` SceneID uuid.UUID `db:"scene_id" json:"scene_id"` } func (q *Queries) DeleteSceneFingerprint(ctx context.Context, arg DeleteSceneFingerprintParams) error { _, err := q.db.Exec(ctx, deleteSceneFingerprint, arg.Hash, arg.Algorithm, arg.UserID, arg.SceneID, ) return err } const deleteSceneFingerprintsByScene = `-- name: DeleteSceneFingerprintsByScene :exec DELETE FROM scene_fingerprints WHERE scene_id = $1 ` func (q *Queries) DeleteSceneFingerprintsByScene(ctx context.Context, sceneID uuid.UUID) error { _, err := q.db.Exec(ctx, deleteSceneFingerprintsByScene, sceneID) return err } const getAllFingerprints = `-- name: GetAllFingerprints :many SELECT SFP.scene_id, FP.hash, FP.algorithm, mode() WITHIN GROUP (ORDER BY SFP.duration)::INTEGER as duration, COUNT(CASE WHEN SFP.vote = 1 THEN 1 END) as submissions, COUNT(CASE WHEN SFP.vote = -1 THEN 1 END) as reports, SUM(SFP.vote) as net_submissions, MIN(SFP.created_at)::TIMESTAMP as created_at, MAX(SFP.created_at)::TIMESTAMP as updated_at, bool_or(SFP.user_id = $1 AND SFP.vote = 1) as user_submitted, bool_or(SFP.user_id = $1 AND SFP.vote = -1) as user_reported FROM scene_fingerprints SFP JOIN fingerprints FP ON SFP.fingerprint_id = FP.id WHERE SFP.scene_id = ANY($2::UUID[]) AND ($3::uuid IS NULL OR SFP.user_id = $3) GROUP BY SFP.scene_id, FP.algorithm, FP.hash ORDER BY net_submissions DESC ` type GetAllFingerprintsParams struct { CurrentUserID uuid.UUID `db:"current_user_id" json:"current_user_id"` SceneIds []uuid.UUID `db:"scene_ids" json:"scene_ids"` FilterUserID uuid.NullUUID `db:"filter_user_id" json:"filter_user_id"` } type GetAllFingerprintsRow struct { SceneID uuid.UUID `db:"scene_id" json:"scene_id"` Hash int64 `db:"hash" json:"hash"` Algorithm string `db:"algorithm" json:"algorithm"` Duration int `db:"duration" json:"duration"` Submissions int64 `db:"submissions" json:"submissions"` Reports int64 `db:"reports" json:"reports"` NetSubmissions int64 `db:"net_submissions" json:"net_submissions"` CreatedAt time.Time `db:"created_at" json:"created_at"` UpdatedAt time.Time `db:"updated_at" json:"updated_at"` UserSubmitted bool `db:"user_submitted" json:"user_submitted"` UserReported bool `db:"user_reported" json:"user_reported"` } // Get all fingerprints for multiple scenes with aggregated vote data // When onlySubmitted is true, pass the actual user ID, when false pass NULL func (q *Queries) GetAllFingerprints(ctx context.Context, arg GetAllFingerprintsParams) ([]GetAllFingerprintsRow, error) { rows, err := q.db.Query(ctx, getAllFingerprints, arg.CurrentUserID, arg.SceneIds, arg.FilterUserID) if err != nil { return nil, err } defer rows.Close() items := []GetAllFingerprintsRow{} for rows.Next() { var i GetAllFingerprintsRow if err := rows.Scan( &i.SceneID, &i.Hash, &i.Algorithm, &i.Duration, &i.Submissions, &i.Reports, &i.NetSubmissions, &i.CreatedAt, &i.UpdatedAt, &i.UserSubmitted, &i.UserReported, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getAllSceneFingerprints = `-- name: GetAllSceneFingerprints :many SELECT f.algorithm, f.hash, sf.duration, sf.created_at, sf.user_id FROM scene_fingerprints sf JOIN fingerprints f ON sf.fingerprint_id = f.id WHERE sf.scene_id = $1 ORDER BY f.algorithm, sf.created_at ` type GetAllSceneFingerprintsRow struct { Algorithm string `db:"algorithm" json:"algorithm"` Hash int64 `db:"hash" json:"hash"` Duration int `db:"duration" json:"duration"` CreatedAt time.Time `db:"created_at" json:"created_at"` UserID uuid.UUID `db:"user_id" json:"user_id"` } func (q *Queries) GetAllSceneFingerprints(ctx context.Context, sceneID uuid.UUID) ([]GetAllSceneFingerprintsRow, error) { rows, err := q.db.Query(ctx, getAllSceneFingerprints, sceneID) if err != nil { return nil, err } defer rows.Close() items := []GetAllSceneFingerprintsRow{} for rows.Next() { var i GetAllSceneFingerprintsRow if err := rows.Scan( &i.Algorithm, &i.Hash, &i.Duration, &i.CreatedAt, &i.UserID, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getFingerprint = `-- name: GetFingerprint :one SELECT id, algorithm, hash FROM fingerprints WHERE hash = $1 AND algorithm = $2 ` type GetFingerprintParams struct { Hash int64 `db:"hash" json:"hash"` Algorithm string `db:"algorithm" json:"algorithm"` } func (q *Queries) GetFingerprint(ctx context.Context, arg GetFingerprintParams) (Fingerprint, error) { row := q.db.QueryRow(ctx, getFingerprint, arg.Hash, arg.Algorithm) var i Fingerprint err := row.Scan(&i.ID, &i.Algorithm, &i.Hash) return i, err } const moveSceneFingerprintSubmissions = `-- name: MoveSceneFingerprintSubmissions :execrows WITH to_move AS ( SELECT SFP.fingerprint_id, SFP.user_id FROM scene_fingerprints SFP JOIN fingerprints FP ON SFP.fingerprint_id = FP.id WHERE FP.hash = $2 AND FP.algorithm = $3 AND SFP.scene_id = $4 ), deleted AS ( DELETE FROM scene_fingerprints WHERE scene_id = $1 AND (fingerprint_id, user_id) IN (SELECT fingerprint_id, user_id FROM to_move) ) UPDATE scene_fingerprints SFP SET scene_id = $1 FROM fingerprints FP WHERE SFP.fingerprint_id = FP.id AND FP.hash = $2 AND FP.algorithm = $3 AND SFP.scene_id = $4 ` type MoveSceneFingerprintSubmissionsParams struct { TargetSceneID uuid.UUID `db:"target_scene_id" json:"target_scene_id"` Hash int64 `db:"hash" json:"hash"` Algorithm string `db:"algorithm" json:"algorithm"` SourceSceneID uuid.UUID `db:"source_scene_id" json:"source_scene_id"` } func (q *Queries) MoveSceneFingerprintSubmissions(ctx context.Context, arg MoveSceneFingerprintSubmissionsParams) (int64, error) { result, err := q.db.Exec(ctx, moveSceneFingerprintSubmissions, arg.TargetSceneID, arg.Hash, arg.Algorithm, arg.SourceSceneID, ) if err != nil { return 0, err } return result.RowsAffected(), nil } const submittedHashExists = `-- name: SubmittedHashExists :one SELECT EXISTS( SELECT 1 FROM scene_fingerprints f JOIN fingerprints fp ON f.fingerprint_id = fp.id WHERE f.scene_id = $1 AND fp.hash = $2 AND fp.algorithm = $3 AND f.vote = 1 ) AS exists ` type SubmittedHashExistsParams struct { SceneID uuid.UUID `db:"scene_id" json:"scene_id"` Hash int64 `db:"hash" json:"hash"` Algorithm string `db:"algorithm" json:"algorithm"` } func (q *Queries) SubmittedHashExists(ctx context.Context, arg SubmittedHashExistsParams) (bool, error) { row := q.db.QueryRow(ctx, submittedHashExists, arg.SceneID, arg.Hash, arg.Algorithm) var exists bool err := row.Scan(&exists) return exists, err } ================================================ FILE: internal/queries/helpers.go ================================================ package queries // DB returns the underlying DBTX interface from Queries func (q *Queries) DB() DBTX { return q.db } ================================================ FILE: internal/queries/image.sql.go ================================================ // Code generated by sqlc. DO NOT EDIT. // versions: // sqlc v1.29.0 // source: image.sql package queries import ( "context" "github.com/gofrs/uuid" ) const createImage = `-- name: CreateImage :one INSERT INTO images (id, url, width, height, checksum) VALUES ($1, $2, $3, $4, $5) RETURNING id, url, width, height, checksum ` type CreateImageParams struct { ID uuid.UUID `db:"id" json:"id"` Url *string `db:"url" json:"url"` Width int `db:"width" json:"width"` Height int `db:"height" json:"height"` Checksum string `db:"checksum" json:"checksum"` } // Image queries func (q *Queries) CreateImage(ctx context.Context, arg CreateImageParams) (Image, error) { row := q.db.QueryRow(ctx, createImage, arg.ID, arg.Url, arg.Width, arg.Height, arg.Checksum, ) var i Image err := row.Scan( &i.ID, &i.Url, &i.Width, &i.Height, &i.Checksum, ) return i, err } const deleteImage = `-- name: DeleteImage :exec DELETE FROM images WHERE id = $1 ` func (q *Queries) DeleteImage(ctx context.Context, id uuid.UUID) error { _, err := q.db.Exec(ctx, deleteImage, id) return err } const findImage = `-- name: FindImage :one SELECT id, url, width, height, checksum FROM images WHERE id = $1 ` func (q *Queries) FindImage(ctx context.Context, id uuid.UUID) (Image, error) { row := q.db.QueryRow(ctx, findImage, id) var i Image err := row.Scan( &i.ID, &i.Url, &i.Width, &i.Height, &i.Checksum, ) return i, err } const findImageByChecksum = `-- name: FindImageByChecksum :one SELECT id, url, width, height, checksum FROM images WHERE checksum = $1 ` func (q *Queries) FindImageByChecksum(ctx context.Context, checksum string) (Image, error) { row := q.db.QueryRow(ctx, findImageByChecksum, checksum) var i Image err := row.Scan( &i.ID, &i.Url, &i.Width, &i.Height, &i.Checksum, ) return i, err } const findImageIdsByPerformerIds = `-- name: FindImageIdsByPerformerIds :many SELECT performer_images.performer_id, performer_images.image_id FROM performer_images WHERE performer_images.performer_id = ANY($1::UUID[]) ` func (q *Queries) FindImageIdsByPerformerIds(ctx context.Context, dollar_1 []uuid.UUID) ([]PerformerImage, error) { rows, err := q.db.Query(ctx, findImageIdsByPerformerIds, dollar_1) if err != nil { return nil, err } defer rows.Close() items := []PerformerImage{} for rows.Next() { var i PerformerImage if err := rows.Scan(&i.PerformerID, &i.ImageID); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const findImageIdsBySceneIds = `-- name: FindImageIdsBySceneIds :many SELECT scene_images.scene_id, scene_images.image_id FROM scene_images WHERE scene_images.scene_id = ANY($1::UUID[]) ` func (q *Queries) FindImageIdsBySceneIds(ctx context.Context, dollar_1 []uuid.UUID) ([]SceneImage, error) { rows, err := q.db.Query(ctx, findImageIdsBySceneIds, dollar_1) if err != nil { return nil, err } defer rows.Close() items := []SceneImage{} for rows.Next() { var i SceneImage if err := rows.Scan(&i.SceneID, &i.ImageID); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const findImageIdsByStudioIds = `-- name: FindImageIdsByStudioIds :many SELECT studio_images.studio_id, studio_images.image_id FROM studio_images WHERE studio_images.studio_id = ANY($1::UUID[]) ` func (q *Queries) FindImageIdsByStudioIds(ctx context.Context, dollar_1 []uuid.UUID) ([]StudioImage, error) { rows, err := q.db.Query(ctx, findImageIdsByStudioIds, dollar_1) if err != nil { return nil, err } defer rows.Close() items := []StudioImage{} for rows.Next() { var i StudioImage if err := rows.Scan(&i.StudioID, &i.ImageID); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const findImagesByIds = `-- name: FindImagesByIds :many SELECT id, url, width, height, checksum FROM images WHERE id = ANY($1::UUID[]) ` func (q *Queries) FindImagesByIds(ctx context.Context, dollar_1 []uuid.UUID) ([]Image, error) { rows, err := q.db.Query(ctx, findImagesByIds, dollar_1) if err != nil { return nil, err } defer rows.Close() items := []Image{} for rows.Next() { var i Image if err := rows.Scan( &i.ID, &i.Url, &i.Width, &i.Height, &i.Checksum, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const findImagesBySceneID = `-- name: FindImagesBySceneID :many SELECT images.id, images.url, images.width, images.height, images.checksum FROM images LEFT JOIN scene_images as scenes_join on scenes_join.image_id = images.id LEFT JOIN scenes on scenes_join.scene_id = scenes.id WHERE scenes.id = $1 ` func (q *Queries) FindImagesBySceneID(ctx context.Context, id uuid.UUID) ([]Image, error) { rows, err := q.db.Query(ctx, findImagesBySceneID, id) if err != nil { return nil, err } defer rows.Close() items := []Image{} for rows.Next() { var i Image if err := rows.Scan( &i.ID, &i.Url, &i.Width, &i.Height, &i.Checksum, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const findImagesByStudioID = `-- name: FindImagesByStudioID :many SELECT images.id, images.url, images.width, images.height, images.checksum FROM images LEFT JOIN studio_images as studios_join on studios_join.image_id = images.id LEFT JOIN studios on studios_join.studio_id = studios.id WHERE studios.id = $1 ` func (q *Queries) FindImagesByStudioID(ctx context.Context, id uuid.UUID) ([]Image, error) { rows, err := q.db.Query(ctx, findImagesByStudioID, id) if err != nil { return nil, err } defer rows.Close() items := []Image{} for rows.Next() { var i Image if err := rows.Scan( &i.ID, &i.Url, &i.Width, &i.Height, &i.Checksum, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const findUnusedImages = `-- name: FindUnusedImages :many SELECT images.id, images.url, images.width, images.height, images.checksum from images LEFT JOIN scene_images ON scene_images.image_id = images.id LEFT JOIN performer_images ON performer_images.image_id = images.id LEFT JOIN studio_images ON studio_images.image_id = images.id LEFT JOIN ( SELECT (jsonb_array_elements(data#>'{new_data,added_images}')->>0)::uuid AS image_id FROM edits WHERE status = 'PENDING' ) edit_images ON edit_images.image_id = images.id LEFT JOIN ( SELECT id, (data->>'image')::uuid AS image_id FROM drafts ) drafts ON images.id = drafts.image_id WHERE scene_images.scene_id IS NULL AND performer_images.performer_id IS NULL AND studio_images.studio_id IS NULL AND edit_images.image_id IS NULL AND drafts.id IS NULL LIMIT 1000 ` func (q *Queries) FindUnusedImages(ctx context.Context) ([]Image, error) { rows, err := q.db.Query(ctx, findUnusedImages) if err != nil { return nil, err } defer rows.Close() items := []Image{} for rows.Next() { var i Image if err := rows.Scan( &i.ID, &i.Url, &i.Width, &i.Height, &i.Checksum, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const isImageUnused = `-- name: IsImageUnused :one SELECT COUNT(*) > 0 AS unused from images LEFT JOIN scene_images ON scene_images.image_id = images.id LEFT JOIN performer_images ON performer_images.image_id = images.id LEFT JOIN studio_images ON studio_images.image_id = images.id LEFT JOIN ( SELECT (jsonb_array_elements(data#>'{new_data,added_images}')->>0)::uuid AS image_id FROM edits WHERE status = 'PENDING' ) edit_images ON edit_images.image_id = images.id LEFT JOIN ( SELECT id, (data->>'image')::uuid AS image_id FROM drafts ) drafts ON images.id = drafts.image_id WHERE images.id = $1 AND scene_images.scene_id IS NULL AND performer_images.performer_id IS NULL AND studio_images.studio_id IS NULL AND edit_images.image_id IS NULL AND drafts.id IS NULL ` func (q *Queries) IsImageUnused(ctx context.Context, id uuid.UUID) (bool, error) { row := q.db.QueryRow(ctx, isImageUnused, id) var unused bool err := row.Scan(&unused) return unused, err } ================================================ FILE: internal/queries/invite_key.sql.go ================================================ // Code generated by sqlc. DO NOT EDIT. // versions: // sqlc v1.29.0 // source: invite_key.sql package queries import ( "context" "time" "github.com/gofrs/uuid" ) const createInviteKey = `-- name: CreateInviteKey :one INSERT INTO invite_keys (id, generated_by, uses, expire_time, generated_at) VALUES ($1, $2, $3, $4, now()) RETURNING id, generated_by, generated_at, uses, expire_time ` type CreateInviteKeyParams struct { ID uuid.UUID `db:"id" json:"id"` GeneratedBy uuid.UUID `db:"generated_by" json:"generated_by"` Uses *int `db:"uses" json:"uses"` ExpireTime *time.Time `db:"expire_time" json:"expire_time"` } // Invite key queries func (q *Queries) CreateInviteKey(ctx context.Context, arg CreateInviteKeyParams) (InviteKey, error) { row := q.db.QueryRow(ctx, createInviteKey, arg.ID, arg.GeneratedBy, arg.Uses, arg.ExpireTime, ) var i InviteKey err := row.Scan( &i.ID, &i.GeneratedBy, &i.GeneratedAt, &i.Uses, &i.ExpireTime, ) return i, err } const deleteInviteKey = `-- name: DeleteInviteKey :exec DELETE FROM invite_keys WHERE id = $1 ` func (q *Queries) DeleteInviteKey(ctx context.Context, id uuid.UUID) error { _, err := q.db.Exec(ctx, deleteInviteKey, id) return err } const destroyExpiredInvites = `-- name: DestroyExpiredInvites :exec DELETE FROM invite_keys WHERE expire_time IS NOT NULL AND expire_time < NOW() ` func (q *Queries) DestroyExpiredInvites(ctx context.Context) error { _, err := q.db.Exec(ctx, destroyExpiredInvites) return err } const findActiveInviteKeysForUser = `-- name: FindActiveInviteKeysForUser :many SELECT i.id, i.generated_by, i.generated_at, i.uses, i.expire_time FROM invite_keys i LEFT JOIN ( SELECT uuid(data->>'invite_key') as invite_key, COUNT(*) as count FROM user_tokens WHERE expires_at > NOW() GROUP BY data->>'invite_key' ) AS used ON used.invite_key = i.id WHERE i.generated_by = $1 AND (i.expire_time IS NULL OR i.expire_time > NOW()) AND (used.invite_key IS NULL OR i.uses IS NULL OR used.count < i.uses) ` func (q *Queries) FindActiveInviteKeysForUser(ctx context.Context, generatedBy uuid.UUID) ([]InviteKey, error) { rows, err := q.db.Query(ctx, findActiveInviteKeysForUser, generatedBy) if err != nil { return nil, err } defer rows.Close() items := []InviteKey{} for rows.Next() { var i InviteKey if err := rows.Scan( &i.ID, &i.GeneratedBy, &i.GeneratedAt, &i.Uses, &i.ExpireTime, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const findInviteKey = `-- name: FindInviteKey :one SELECT id, generated_by, generated_at, uses, expire_time FROM invite_keys WHERE id = $1 ` func (q *Queries) FindInviteKey(ctx context.Context, id uuid.UUID) (InviteKey, error) { row := q.db.QueryRow(ctx, findInviteKey, id) var i InviteKey err := row.Scan( &i.ID, &i.GeneratedBy, &i.GeneratedAt, &i.Uses, &i.ExpireTime, ) return i, err } const inviteKeyUsed = `-- name: InviteKeyUsed :one UPDATE invite_keys SET uses = GREATEST(0, uses - 1) WHERE id = $1 AND uses IS NOT NULL AND uses > 0 RETURNING uses ` func (q *Queries) InviteKeyUsed(ctx context.Context, id uuid.UUID) (*int, error) { row := q.db.QueryRow(ctx, inviteKeyUsed, id) var uses *int err := row.Scan(&uses) return uses, err } ================================================ FILE: internal/queries/mod_audit.sql.go ================================================ // Code generated by sqlc. DO NOT EDIT. // versions: // sqlc v1.29.0 // source: mod_audit.sql package queries import ( "context" "encoding/json" "github.com/gofrs/uuid" ) const createModAudit = `-- name: CreateModAudit :one INSERT INTO mod_audit ( id, action, user_id, target_id, target_type, data, reason, created_at ) VALUES ($1, $2, $3, $4, $5, $6, $7, NOW()) RETURNING id, action, user_id, target_id, target_type, data, reason, created_at ` type CreateModAuditParams struct { ID uuid.UUID `db:"id" json:"id"` Action ModAuditAction `db:"action" json:"action"` UserID uuid.NullUUID `db:"user_id" json:"user_id"` TargetID uuid.UUID `db:"target_id" json:"target_id"` TargetType string `db:"target_type" json:"target_type"` Data json.RawMessage `db:"data" json:"data"` Reason *string `db:"reason" json:"reason"` } func (q *Queries) CreateModAudit(ctx context.Context, arg CreateModAuditParams) (ModAudit, error) { row := q.db.QueryRow(ctx, createModAudit, arg.ID, arg.Action, arg.UserID, arg.TargetID, arg.TargetType, arg.Data, arg.Reason, ) var i ModAudit err := row.Scan( &i.ID, &i.Action, &i.UserID, &i.TargetID, &i.TargetType, &i.Data, &i.Reason, &i.CreatedAt, ) return i, err } const deleteExpiredModAudits = `-- name: DeleteExpiredModAudits :exec DELETE FROM mod_audit WHERE created_at < NOW() - INTERVAL '1 day' * $1 ` func (q *Queries) DeleteExpiredModAudits(ctx context.Context, dollar_1 interface{}) error { _, err := q.db.Exec(ctx, deleteExpiredModAudits, dollar_1) return err } const getModAuditCount = `-- name: GetModAuditCount :one SELECT COUNT(*) FROM mod_audit WHERE ($1::mod_audit_action IS NULL OR action = $1) AND ($2::uuid IS NULL OR user_id = $2) ` type GetModAuditCountParams struct { Action NullModAuditAction `db:"action" json:"action"` UserID uuid.NullUUID `db:"user_id" json:"user_id"` } func (q *Queries) GetModAuditCount(ctx context.Context, arg GetModAuditCountParams) (int64, error) { row := q.db.QueryRow(ctx, getModAuditCount, arg.Action, arg.UserID) var count int64 err := row.Scan(&count) return count, err } const queryModAudits = `-- name: QueryModAudits :many SELECT id, action, user_id, target_id, target_type, data, reason, created_at FROM mod_audit WHERE ($3::mod_audit_action IS NULL OR action = $3) AND ($4::uuid IS NULL OR user_id = $4) ORDER BY created_at DESC LIMIT $1 OFFSET $2 ` type QueryModAuditsParams struct { Limit int32 `db:"limit" json:"limit"` Offset int32 `db:"offset" json:"offset"` Action NullModAuditAction `db:"action" json:"action"` UserID uuid.NullUUID `db:"user_id" json:"user_id"` } func (q *Queries) QueryModAudits(ctx context.Context, arg QueryModAuditsParams) ([]ModAudit, error) { rows, err := q.db.Query(ctx, queryModAudits, arg.Limit, arg.Offset, arg.Action, arg.UserID, ) if err != nil { return nil, err } defer rows.Close() items := []ModAudit{} for rows.Next() { var i ModAudit if err := rows.Scan( &i.ID, &i.Action, &i.UserID, &i.TargetID, &i.TargetType, &i.Data, &i.Reason, &i.CreatedAt, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } ================================================ FILE: internal/queries/models.go ================================================ // Code generated by sqlc. DO NOT EDIT. // versions: // sqlc v1.29.0 package queries import ( "database/sql/driver" "encoding/json" "fmt" "time" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" ) type ModAuditAction string const ( ModAuditActionEDITDELETE ModAuditAction = "EDIT_DELETE" ModAuditActionEDITAMENDMENT ModAuditAction = "EDIT_AMENDMENT" ) func (e *ModAuditAction) Scan(src interface{}) error { switch s := src.(type) { case []byte: *e = ModAuditAction(s) case string: *e = ModAuditAction(s) default: return fmt.Errorf("unsupported scan type for ModAuditAction: %T", src) } return nil } type NullModAuditAction struct { ModAuditAction ModAuditAction `json:"mod_audit_action"` Valid bool `json:"valid"` // Valid is true if ModAuditAction is not NULL } // Scan implements the Scanner interface. func (ns *NullModAuditAction) Scan(value interface{}) error { if value == nil { ns.ModAuditAction, ns.Valid = "", false return nil } ns.Valid = true return ns.ModAuditAction.Scan(value) } // Value implements the driver Valuer interface. func (ns NullModAuditAction) Value() (driver.Value, error) { if !ns.Valid { return nil, nil } return string(ns.ModAuditAction), nil } type NotificationType string const ( NotificationTypeFAVORITEPERFORMERSCENE NotificationType = "FAVORITE_PERFORMER_SCENE" NotificationTypeFAVORITEPERFORMEREDIT NotificationType = "FAVORITE_PERFORMER_EDIT" NotificationTypeFAVORITESTUDIOSCENE NotificationType = "FAVORITE_STUDIO_SCENE" NotificationTypeFAVORITESTUDIOEDIT NotificationType = "FAVORITE_STUDIO_EDIT" NotificationTypeCOMMENTOWNEDIT NotificationType = "COMMENT_OWN_EDIT" NotificationTypeDOWNVOTEOWNEDIT NotificationType = "DOWNVOTE_OWN_EDIT" NotificationTypeFAILEDOWNEDIT NotificationType = "FAILED_OWN_EDIT" NotificationTypeCOMMENTCOMMENTEDEDIT NotificationType = "COMMENT_COMMENTED_EDIT" NotificationTypeCOMMENTVOTEDEDIT NotificationType = "COMMENT_VOTED_EDIT" NotificationTypeUPDATEDEDIT NotificationType = "UPDATED_EDIT" NotificationTypeFINGERPRINTEDSCENEEDIT NotificationType = "FINGERPRINTED_SCENE_EDIT" ) func (e *NotificationType) Scan(src interface{}) error { switch s := src.(type) { case []byte: *e = NotificationType(s) case string: *e = NotificationType(s) default: return fmt.Errorf("unsupported scan type for NotificationType: %T", src) } return nil } type NullNotificationType struct { NotificationType NotificationType `json:"notification_type"` Valid bool `json:"valid"` // Valid is true if NotificationType is not NULL } // Scan implements the Scanner interface. func (ns *NullNotificationType) Scan(value interface{}) error { if value == nil { ns.NotificationType, ns.Valid = "", false return nil } ns.Valid = true return ns.NotificationType.Scan(value) } // Value implements the driver Valuer interface. func (ns NullNotificationType) Value() (driver.Value, error) { if !ns.Valid { return nil, nil } return string(ns.NotificationType), nil } type Draft struct { ID uuid.UUID `db:"id" json:"id"` UserID uuid.UUID `db:"user_id" json:"user_id"` Type string `db:"type" json:"type"` Data json.RawMessage `db:"data" json:"data"` CreatedAt time.Time `db:"created_at" json:"created_at"` } type Edit struct { ID uuid.UUID `db:"id" json:"id"` UserID uuid.NullUUID `db:"user_id" json:"user_id"` Operation string `db:"operation" json:"operation"` TargetType string `db:"target_type" json:"target_type"` Data []byte `db:"data" json:"data"` Votes int `db:"votes" json:"votes"` Status string `db:"status" json:"status"` Applied bool `db:"applied" json:"applied"` CreatedAt time.Time `db:"created_at" json:"created_at"` UpdatedAt *time.Time `db:"updated_at" json:"updated_at"` ClosedAt *time.Time `db:"closed_at" json:"closed_at"` Bot bool `db:"bot" json:"bot"` UpdateCount int `db:"update_count" json:"update_count"` } type EditComment struct { ID uuid.UUID `db:"id" json:"id"` EditID uuid.UUID `db:"edit_id" json:"edit_id"` UserID uuid.NullUUID `db:"user_id" json:"user_id"` CreatedAt time.Time `db:"created_at" json:"created_at"` Text string `db:"text" json:"text"` } type EditVote struct { EditID uuid.UUID `db:"edit_id" json:"edit_id"` UserID uuid.UUID `db:"user_id" json:"user_id"` CreatedAt time.Time `db:"created_at" json:"created_at"` Vote string `db:"vote" json:"vote"` } type Fingerprint struct { ID int `db:"id" json:"id"` Algorithm string `db:"algorithm" json:"algorithm"` Hash int64 `db:"hash" json:"hash"` } type Image struct { ID uuid.UUID `db:"id" json:"id"` Url *string `db:"url" json:"url"` Width int `db:"width" json:"width"` Height int `db:"height" json:"height"` Checksum string `db:"checksum" json:"checksum"` } type InviteKey struct { ID uuid.UUID `db:"id" json:"id"` GeneratedBy uuid.UUID `db:"generated_by" json:"generated_by"` GeneratedAt time.Time `db:"generated_at" json:"generated_at"` Uses *int `db:"uses" json:"uses"` ExpireTime *time.Time `db:"expire_time" json:"expire_time"` } type ModAudit struct { ID uuid.UUID `db:"id" json:"id"` Action ModAuditAction `db:"action" json:"action"` UserID uuid.NullUUID `db:"user_id" json:"user_id"` TargetID uuid.UUID `db:"target_id" json:"target_id"` TargetType string `db:"target_type" json:"target_type"` Data json.RawMessage `db:"data" json:"data"` Reason *string `db:"reason" json:"reason"` CreatedAt time.Time `db:"created_at" json:"created_at"` } type Notification struct { UserID uuid.UUID `db:"user_id" json:"user_id"` Type NotificationType `db:"type" json:"type"` ID uuid.UUID `db:"id" json:"id"` CreatedAt time.Time `db:"created_at" json:"created_at"` ReadAt *time.Time `db:"read_at" json:"read_at"` } type Performer struct { ID uuid.UUID `db:"id" json:"id"` Name string `db:"name" json:"name"` Disambiguation *string `db:"disambiguation" json:"disambiguation"` Gender *models.GenderEnum `db:"gender" json:"gender"` Ethnicity *models.EthnicityEnum `db:"ethnicity" json:"ethnicity"` Country *string `db:"country" json:"country"` EyeColor *models.EyeColorEnum `db:"eye_color" json:"eye_color"` HairColor *models.HairColorEnum `db:"hair_color" json:"hair_color"` Height *int `db:"height" json:"height"` CupSize *string `db:"cup_size" json:"cup_size"` BandSize *int `db:"band_size" json:"band_size"` HipSize *int `db:"hip_size" json:"hip_size"` WaistSize *int `db:"waist_size" json:"waist_size"` BreastType *models.BreastTypeEnum `db:"breast_type" json:"breast_type"` CareerStartYear *int `db:"career_start_year" json:"career_start_year"` CareerEndYear *int `db:"career_end_year" json:"career_end_year"` CreatedAt time.Time `db:"created_at" json:"created_at"` UpdatedAt time.Time `db:"updated_at" json:"updated_at"` Deleted bool `db:"deleted" json:"deleted"` Birthdate *string `db:"birthdate" json:"birthdate"` Deathdate *string `db:"deathdate" json:"deathdate"` } type PerformerAlias struct { PerformerID uuid.UUID `db:"performer_id" json:"performer_id"` Alias string `db:"alias" json:"alias"` } type PerformerEdit struct { EditID uuid.UUID `db:"edit_id" json:"edit_id"` PerformerID uuid.UUID `db:"performer_id" json:"performer_id"` } type PerformerFavorite struct { PerformerID uuid.UUID `db:"performer_id" json:"performer_id"` UserID uuid.UUID `db:"user_id" json:"user_id"` CreatedAt *time.Time `db:"created_at" json:"created_at"` } type PerformerImage struct { PerformerID uuid.UUID `db:"performer_id" json:"performer_id"` ImageID uuid.UUID `db:"image_id" json:"image_id"` } type PerformerPiercing struct { PerformerID uuid.UUID `db:"performer_id" json:"performer_id"` Location *string `db:"location" json:"location"` Description *string `db:"description" json:"description"` } type PerformerRedirect struct { SourceID uuid.UUID `db:"source_id" json:"source_id"` TargetID uuid.UUID `db:"target_id" json:"target_id"` } type PerformerSearch struct { PerformerID uuid.UUID `db:"performer_id" json:"performer_id"` Name *string `db:"name" json:"name"` Disambiguation *string `db:"disambiguation" json:"disambiguation"` Aliases []string `db:"aliases" json:"aliases"` Gender *string `db:"gender" json:"gender"` } type PerformerTattoo struct { PerformerID uuid.UUID `db:"performer_id" json:"performer_id"` Location *string `db:"location" json:"location"` Description *string `db:"description" json:"description"` } type PerformerUrl struct { PerformerID uuid.UUID `db:"performer_id" json:"performer_id"` Url string `db:"url" json:"url"` SiteID uuid.UUID `db:"site_id" json:"site_id"` } type Scene struct { ID uuid.UUID `db:"id" json:"id"` Title *string `db:"title" json:"title"` Details *string `db:"details" json:"details"` StudioID uuid.NullUUID `db:"studio_id" json:"studio_id"` CreatedAt time.Time `db:"created_at" json:"created_at"` UpdatedAt time.Time `db:"updated_at" json:"updated_at"` Duration *int `db:"duration" json:"duration"` Director *string `db:"director" json:"director"` Deleted bool `db:"deleted" json:"deleted"` Code *string `db:"code" json:"code"` Date *string `db:"date" json:"date"` ProductionDate *string `db:"production_date" json:"production_date"` } type SceneEdit struct { EditID uuid.UUID `db:"edit_id" json:"edit_id"` SceneID uuid.UUID `db:"scene_id" json:"scene_id"` } type SceneFingerprint struct { FingerprintID int `db:"fingerprint_id" json:"fingerprint_id"` SceneID uuid.UUID `db:"scene_id" json:"scene_id"` UserID uuid.UUID `db:"user_id" json:"user_id"` Duration int `db:"duration" json:"duration"` CreatedAt time.Time `db:"created_at" json:"created_at"` Vote int16 `db:"vote" json:"vote"` } type SceneImage struct { SceneID uuid.UUID `db:"scene_id" json:"scene_id"` ImageID uuid.UUID `db:"image_id" json:"image_id"` } type ScenePerformer struct { SceneID uuid.UUID `db:"scene_id" json:"scene_id"` As *string `db:"as" json:"as"` PerformerID uuid.UUID `db:"performer_id" json:"performer_id"` } type SceneRedirect struct { SourceID uuid.UUID `db:"source_id" json:"source_id"` TargetID uuid.UUID `db:"target_id" json:"target_id"` } type SceneSearch struct { SceneID uuid.UUID `db:"scene_id" json:"scene_id"` SceneTitle *string `db:"scene_title" json:"scene_title"` SceneDate *string `db:"scene_date" json:"scene_date"` StudioName *string `db:"studio_name" json:"studio_name"` NetworkName *string `db:"network_name" json:"network_name"` PerformerNames []string `db:"performer_names" json:"performer_names"` SceneCode *string `db:"scene_code" json:"scene_code"` } type SceneTag struct { SceneID uuid.UUID `db:"scene_id" json:"scene_id"` TagID uuid.UUID `db:"tag_id" json:"tag_id"` } type SceneUrl struct { SceneID uuid.UUID `db:"scene_id" json:"scene_id"` Url string `db:"url" json:"url"` SiteID uuid.UUID `db:"site_id" json:"site_id"` } type Site struct { ID uuid.UUID `db:"id" json:"id"` Name string `db:"name" json:"name"` Description *string `db:"description" json:"description"` Url *string `db:"url" json:"url"` Regex *string `db:"regex" json:"regex"` ValidTypes []string `db:"valid_types" json:"valid_types"` CreatedAt time.Time `db:"created_at" json:"created_at"` UpdatedAt time.Time `db:"updated_at" json:"updated_at"` } type Studio struct { ID uuid.UUID `db:"id" json:"id"` Name string `db:"name" json:"name"` ParentStudioID uuid.NullUUID `db:"parent_studio_id" json:"parent_studio_id"` CreatedAt time.Time `db:"created_at" json:"created_at"` UpdatedAt time.Time `db:"updated_at" json:"updated_at"` Deleted bool `db:"deleted" json:"deleted"` } type StudioAlias struct { StudioID uuid.UUID `db:"studio_id" json:"studio_id"` Alias string `db:"alias" json:"alias"` } type StudioEdit struct { EditID uuid.UUID `db:"edit_id" json:"edit_id"` StudioID uuid.UUID `db:"studio_id" json:"studio_id"` } type StudioFavorite struct { StudioID uuid.UUID `db:"studio_id" json:"studio_id"` UserID uuid.UUID `db:"user_id" json:"user_id"` CreatedAt *time.Time `db:"created_at" json:"created_at"` } type StudioImage struct { StudioID uuid.UUID `db:"studio_id" json:"studio_id"` ImageID uuid.UUID `db:"image_id" json:"image_id"` } type StudioRedirect struct { SourceID uuid.UUID `db:"source_id" json:"source_id"` TargetID uuid.UUID `db:"target_id" json:"target_id"` } type StudioSearch struct { StudioID uuid.UUID `db:"studio_id" json:"studio_id"` Name *string `db:"name" json:"name"` Network *string `db:"network" json:"network"` Aliases []string `db:"aliases" json:"aliases"` } type StudioUrl struct { StudioID uuid.UUID `db:"studio_id" json:"studio_id"` Url string `db:"url" json:"url"` SiteID uuid.UUID `db:"site_id" json:"site_id"` } type Tag struct { ID uuid.UUID `db:"id" json:"id"` Name string `db:"name" json:"name"` Description *string `db:"description" json:"description"` CreatedAt time.Time `db:"created_at" json:"created_at"` UpdatedAt time.Time `db:"updated_at" json:"updated_at"` Deleted bool `db:"deleted" json:"deleted"` CategoryID uuid.NullUUID `db:"category_id" json:"category_id"` } type TagAlias struct { TagID uuid.UUID `db:"tag_id" json:"tag_id"` Alias string `db:"alias" json:"alias"` } type TagCategory struct { ID uuid.UUID `db:"id" json:"id"` Group string `db:"group" json:"group"` Name string `db:"name" json:"name"` Description *string `db:"description" json:"description"` CreatedAt time.Time `db:"created_at" json:"created_at"` UpdatedAt time.Time `db:"updated_at" json:"updated_at"` } type TagEdit struct { EditID uuid.UUID `db:"edit_id" json:"edit_id"` TagID uuid.UUID `db:"tag_id" json:"tag_id"` } type TagRedirect struct { SourceID uuid.UUID `db:"source_id" json:"source_id"` TargetID uuid.UUID `db:"target_id" json:"target_id"` } type TagSearch struct { TagID uuid.UUID `db:"tag_id" json:"tag_id"` Name *string `db:"name" json:"name"` Aliases []string `db:"aliases" json:"aliases"` } type User struct { ID uuid.UUID `db:"id" json:"id"` Name string `db:"name" json:"name"` PasswordHash string `db:"password_hash" json:"password_hash"` Email string `db:"email" json:"email"` ApiKey string `db:"api_key" json:"api_key"` ApiCalls *int `db:"api_calls" json:"api_calls"` LastApiCall time.Time `db:"last_api_call" json:"last_api_call"` CreatedAt time.Time `db:"created_at" json:"created_at"` UpdatedAt time.Time `db:"updated_at" json:"updated_at"` InvitedBy uuid.NullUUID `db:"invited_by" json:"invited_by"` InviteTokens int `db:"invite_tokens" json:"invite_tokens"` } type UserNotification struct { UserID uuid.UUID `db:"user_id" json:"user_id"` Type NotificationType `db:"type" json:"type"` } type UserRole struct { UserID uuid.UUID `db:"user_id" json:"user_id"` Role string `db:"role" json:"role"` } type UserToken struct { ID uuid.UUID `db:"id" json:"id"` Data []byte `db:"data" json:"data"` Type string `db:"type" json:"type"` CreatedAt time.Time `db:"created_at" json:"created_at"` ExpiresAt time.Time `db:"expires_at" json:"expires_at"` } ================================================ FILE: internal/queries/notification.sql.go ================================================ // Code generated by sqlc. DO NOT EDIT. // versions: // sqlc v1.29.0 // source: notification.sql package queries import ( "context" "github.com/gofrs/uuid" ) const countNotificationsByUser = `-- name: CountNotificationsByUser :one SELECT COUNT(*) FROM notifications WHERE user_id = $1 AND ($2::boolean = FALSE OR read_at IS NULL) AND ($3::notification_type IS NULL OR type = $3::notification_type) ` type CountNotificationsByUserParams struct { UserID uuid.UUID `db:"user_id" json:"user_id"` UnreadOnly bool `db:"unread_only" json:"unread_only"` Type NullNotificationType `db:"type" json:"type"` } func (q *Queries) CountNotificationsByUser(ctx context.Context, arg CountNotificationsByUserParams) (int64, error) { row := q.db.QueryRow(ctx, countNotificationsByUser, arg.UserID, arg.UnreadOnly, arg.Type) var count int64 err := row.Scan(&count) return count, err } type CreateUserNotificationSubscriptionsParams struct { UserID uuid.UUID `db:"user_id" json:"user_id"` Type NotificationType `db:"type" json:"type"` } const deleteUserNotificationSubscriptions = `-- name: DeleteUserNotificationSubscriptions :exec DELETE FROM user_notifications WHERE user_id = $1 ` func (q *Queries) DeleteUserNotificationSubscriptions(ctx context.Context, userID uuid.UUID) error { _, err := q.db.Exec(ctx, deleteUserNotificationSubscriptions, userID) return err } const destroyExpiredNotifications = `-- name: DestroyExpiredNotifications :exec DELETE FROM notifications WHERE read_at < CURRENT_DATE - INTERVAL '1 day' OR created_at < CURRENT_DATE - INTERVAL '14 day' ` func (q *Queries) DestroyExpiredNotifications(ctx context.Context) error { _, err := q.db.Exec(ctx, destroyExpiredNotifications) return err } const findNotificationsByUser = `-- name: FindNotificationsByUser :many SELECT user_id, type, id, created_at, read_at FROM notifications WHERE user_id = $1 AND ($4::notification_type IS NULL OR type = $4::notification_type) ORDER BY created_at DESC LIMIT $2 OFFSET $3 ` type FindNotificationsByUserParams struct { UserID uuid.UUID `db:"user_id" json:"user_id"` Limit int32 `db:"limit" json:"limit"` Offset int32 `db:"offset" json:"offset"` Type NullNotificationType `db:"type" json:"type"` } // Notification queries func (q *Queries) FindNotificationsByUser(ctx context.Context, arg FindNotificationsByUserParams) ([]Notification, error) { rows, err := q.db.Query(ctx, findNotificationsByUser, arg.UserID, arg.Limit, arg.Offset, arg.Type, ) if err != nil { return nil, err } defer rows.Close() items := []Notification{} for rows.Next() { var i Notification if err := rows.Scan( &i.UserID, &i.Type, &i.ID, &i.CreatedAt, &i.ReadAt, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const findUnreadNotificationsByUser = `-- name: FindUnreadNotificationsByUser :many SELECT user_id, type, id, created_at, read_at FROM notifications WHERE user_id = $1 AND read_at IS NULL AND ($4::notification_type IS NULL OR type = $4::notification_type) ORDER BY created_at DESC LIMIT $2 OFFSET $3 ` type FindUnreadNotificationsByUserParams struct { UserID uuid.UUID `db:"user_id" json:"user_id"` Limit int32 `db:"limit" json:"limit"` Offset int32 `db:"offset" json:"offset"` Type NullNotificationType `db:"type" json:"type"` } func (q *Queries) FindUnreadNotificationsByUser(ctx context.Context, arg FindUnreadNotificationsByUserParams) ([]Notification, error) { rows, err := q.db.Query(ctx, findUnreadNotificationsByUser, arg.UserID, arg.Limit, arg.Offset, arg.Type, ) if err != nil { return nil, err } defer rows.Close() items := []Notification{} for rows.Next() { var i Notification if err := rows.Scan( &i.UserID, &i.Type, &i.ID, &i.CreatedAt, &i.ReadAt, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const markAllNotificationsRead = `-- name: MarkAllNotificationsRead :exec UPDATE notifications SET read_at = NOW() WHERE user_id = $1 AND read_at IS NULL ` func (q *Queries) MarkAllNotificationsRead(ctx context.Context, userID uuid.UUID) error { _, err := q.db.Exec(ctx, markAllNotificationsRead, userID) return err } const markNotificationRead = `-- name: MarkNotificationRead :exec UPDATE notifications SET read_at = NOW() WHERE user_id = $1 AND type = $2 AND id = $3 AND read_at IS NULL ` type MarkNotificationReadParams struct { UserID uuid.UUID `db:"user_id" json:"user_id"` Type NotificationType `db:"type" json:"type"` ID uuid.UUID `db:"id" json:"id"` } func (q *Queries) MarkNotificationRead(ctx context.Context, arg MarkNotificationReadParams) error { _, err := q.db.Exec(ctx, markNotificationRead, arg.UserID, arg.Type, arg.ID) return err } const triggerDownvoteEditNotifications = `-- name: TriggerDownvoteEditNotifications :exec INSERT INTO notifications (user_id, type, id) SELECT N.user_id, N.type, $1 FROM edits E JOIN user_notifications N ON E.user_id = N.user_id AND N.type = 'DOWNVOTE_OWN_EDIT' WHERE E.id = $1 ` func (q *Queries) TriggerDownvoteEditNotifications(ctx context.Context, id uuid.UUID) error { _, err := q.db.Exec(ctx, triggerDownvoteEditNotifications, id) return err } const triggerEditCommentNotifications = `-- name: TriggerEditCommentNotifications :exec INSERT INTO notifications (user_id, type, id) SELECT DISTINCT ON (user_id) user_id, type, $1 FROM ( SELECT N.user_id, N.type, 1 as ordering FROM edit_comments EC JOIN edits E ON EC.edit_id = E.id JOIN user_notifications N ON E.user_id = N.user_id AND N.type = 'COMMENT_OWN_EDIT' WHERE E.user_id != EC.user_id AND EC.id = $1 UNION SELECT N.user_id, N.type, 2 as ordering FROM edit_comments EC JOIN edits E ON EC.edit_id = E.id JOIN edit_comments EO ON EO.edit_id = E.id JOIN user_notifications N ON EO.user_id = N.user_id AND N.type = 'COMMENT_COMMENTED_EDIT' WHERE EO.user_id != E.user_id AND EO.user_id != EC.user_id AND EC.id = $1 UNION SELECT N.user_id, N.type, 3 as ordering FROM edit_comments EC JOIN edits E ON EC.edit_id = E.id JOIN edit_votes EV ON EV.edit_id = E.id JOIN user_notifications N ON EV.user_id = N.user_id AND N.type = 'COMMENT_VOTED_EDIT' WHERE EV.vote != 'ABSTAIN' AND EV.user_id != E.user_id AND EV.user_id != EC.user_id AND EC.id = $1 ) notifications ORDER BY user_id, ordering ASC ` func (q *Queries) TriggerEditCommentNotifications(ctx context.Context, id uuid.UUID) error { _, err := q.db.Exec(ctx, triggerEditCommentNotifications, id) return err } const triggerFailedEditNotifications = `-- name: TriggerFailedEditNotifications :exec INSERT INTO notifications (user_id, type, id) SELECT N.user_id, N.type, $1 FROM edits E JOIN user_notifications N ON E.user_id = N.user_id AND N.type = 'FAILED_OWN_EDIT' WHERE E.id = $1 ` func (q *Queries) TriggerFailedEditNotifications(ctx context.Context, id uuid.UUID) error { _, err := q.db.Exec(ctx, triggerFailedEditNotifications, id) return err } const triggerPerformerEditNotifications = `-- name: TriggerPerformerEditNotifications :exec INSERT INTO notifications (user_id, type, id) SELECT N.user_id, N.type, $1 FROM performer_edits PE JOIN edits E ON PE.edit_id = E.id JOIN performer_favorites PF ON PE.performer_id = PF.performer_id JOIN user_notifications N ON PF.user_id = N.user_id AND N.type = 'FAVORITE_PERFORMER_EDIT' AND N.user_id != E.user_id WHERE PE.edit_id = $1 ` func (q *Queries) TriggerPerformerEditNotifications(ctx context.Context, id uuid.UUID) error { _, err := q.db.Exec(ctx, triggerPerformerEditNotifications, id) return err } const triggerSceneCreationNotifications = `-- name: TriggerSceneCreationNotifications :exec INSERT INTO notifications (user_id, type, id) SELECT N.user_id, N.type, $1 as id FROM scenes S JOIN scene_edits SE ON S.id = SE.scene_id JOIN edits E ON SE.edit_id = E.id AND E.operation = 'CREATE' JOIN studio_favorites SF ON S.studio_id = SF.studio_id JOIN user_notifications N ON SF.user_id = N.user_id AND N.type = 'FAVORITE_STUDIO_SCENE' AND E.user_id != N.user_id WHERE S.id = $1 UNION SELECT N.user_id, N.type, $1 as id FROM scene_performers SP JOIN scene_edits SE ON SP.scene_id = SE.scene_id JOIN edits E ON SE.edit_id = E.id AND E.operation = 'CREATE' JOIN performer_favorites PF ON SP.performer_id = PF.performer_id JOIN user_notifications N ON PF.user_id = N.user_id AND N.type = 'FAVORITE_PERFORMER_SCENE' AND E.user_id != N.user_id WHERE SP.scene_id = $1 ` func (q *Queries) TriggerSceneCreationNotifications(ctx context.Context, id uuid.UUID) error { _, err := q.db.Exec(ctx, triggerSceneCreationNotifications, id) return err } const triggerSceneEditNotifications = `-- name: TriggerSceneEditNotifications :exec INSERT INTO notifications (user_id, type, id) SELECT DISTINCT ON (user_id) user_id, type, $1 FROM ( SELECT N.user_id, N.type FROM edits E JOIN studio_favorites SF ON (E.data->'new_data'->>'studio_id')::uuid = SF.studio_id JOIN user_notifications N ON SF.user_id = N.user_id AND N.type = 'FAVORITE_STUDIO_EDIT' AND N.user_id != E.user_id WHERE E.id = $1 UNION SELECT N.user_id, N.type FROM edits E JOIN scene_edits SE ON E.id = SE.edit_id JOIN scenes S ON SE.scene_id = S.id JOIN studio_favorites SF ON S.studio_id = SF.studio_id JOIN user_notifications N ON SF.user_id = N.user_id AND N.type = 'FAVORITE_STUDIO_EDIT' AND N.user_id != E.user_id WHERE E.id = $1 UNION SELECT N.user_id, N.type FROM ( SELECT id, (jsonb_array_elements(edits.data->'new_data'->'added_performers')->>'performer_id')::uuid AS performer_id, user_id FROM edits ) E JOIN performer_favorites PF ON E.performer_id = PF.performer_id JOIN user_notifications N ON PF.user_id = N.user_id AND N.type = 'FAVORITE_PERFORMER_EDIT' AND N.user_id != E.user_id WHERE E.id = $1 UNION SELECT N.user_id, N.type FROM edits E JOIN scene_edits SE ON E.id = SE.edit_id JOIN scene_performers SP ON SP.scene_id = SE.scene_id JOIN performer_favorites PF ON PF.performer_id = SP.performer_id JOIN user_notifications N ON PF.user_id = N.user_id AND N.type = 'FAVORITE_PERFORMER_EDIT' AND N.user_id != E.user_id WHERE E.id = $1 UNION SELECT N.user_id, N.type FROM edits E JOIN scene_edits SE ON E.id = SE.edit_id JOIN scene_fingerprints SF ON SE.scene_id = SF.scene_id JOIN user_notifications N ON SF.user_id = N.user_id AND N.type = 'FINGERPRINTED_SCENE_EDIT' AND N.user_id != E.user_id WHERE E.id = $1 ) notifications ` func (q *Queries) TriggerSceneEditNotifications(ctx context.Context, id uuid.UUID) error { _, err := q.db.Exec(ctx, triggerSceneEditNotifications, id) return err } const triggerStudioEditNotifications = `-- name: TriggerStudioEditNotifications :exec INSERT INTO notifications (user_id, type, id) SELECT N.user_id, N.type, $1 FROM studio_edits SE JOIN edits E ON SE.edit_id = E.id JOIN studio_favorites SF ON SE.studio_id = SF.studio_id JOIN user_notifications N ON SF.user_id = N.user_id AND N.type = 'FAVORITE_STUDIO_EDIT' AND N.user_id != E.user_id WHERE SE.edit_id = $1 ` func (q *Queries) TriggerStudioEditNotifications(ctx context.Context, id uuid.UUID) error { _, err := q.db.Exec(ctx, triggerStudioEditNotifications, id) return err } const triggerUpdatedEditNotifications = `-- name: TriggerUpdatedEditNotifications :exec INSERT INTO notifications (user_id, type, id) SELECT N.user_id, N.type, $1 FROM edits E JOIN edit_votes EV ON E.id = EV.edit_id JOIN user_notifications N ON EV.user_id = N.user_id AND N.type = 'UPDATED_EDIT' WHERE E.id = $1 ` func (q *Queries) TriggerUpdatedEditNotifications(ctx context.Context, id uuid.UUID) error { _, err := q.db.Exec(ctx, triggerUpdatedEditNotifications, id) return err } ================================================ FILE: internal/queries/performer.sql.go ================================================ // Code generated by sqlc. DO NOT EDIT. // versions: // sqlc v1.29.0 // source: performer.sql package queries import ( "context" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" ) const clearScenePerformerAlias = `-- name: ClearScenePerformerAlias :exec UPDATE scene_performers SET "as" = NULL WHERE performer_id = $1 AND "as" = $2 ` type ClearScenePerformerAliasParams struct { PerformerID uuid.UUID `db:"performer_id" json:"performer_id"` As *string `db:"as" json:"as"` } func (q *Queries) ClearScenePerformerAlias(ctx context.Context, arg ClearScenePerformerAliasParams) error { _, err := q.db.Exec(ctx, clearScenePerformerAlias, arg.PerformerID, arg.As) return err } const createPerformer = `-- name: CreatePerformer :one INSERT INTO performers ( id, name, disambiguation, gender, birthdate, ethnicity, country, eye_color, hair_color, height, cup_size, band_size, hip_size, waist_size, breast_type, career_start_year, career_end_year, deathdate, created_at, updated_at ) VALUES ( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, now(), now() ) RETURNING id, name, disambiguation, gender, ethnicity, country, eye_color, hair_color, height, cup_size, band_size, hip_size, waist_size, breast_type, career_start_year, career_end_year, created_at, updated_at, deleted, birthdate, deathdate ` type CreatePerformerParams struct { ID uuid.UUID `db:"id" json:"id"` Name string `db:"name" json:"name"` Disambiguation *string `db:"disambiguation" json:"disambiguation"` Gender *models.GenderEnum `db:"gender" json:"gender"` Birthdate *string `db:"birthdate" json:"birthdate"` Ethnicity *models.EthnicityEnum `db:"ethnicity" json:"ethnicity"` Country *string `db:"country" json:"country"` EyeColor *models.EyeColorEnum `db:"eye_color" json:"eye_color"` HairColor *models.HairColorEnum `db:"hair_color" json:"hair_color"` Height *int `db:"height" json:"height"` CupSize *string `db:"cup_size" json:"cup_size"` BandSize *int `db:"band_size" json:"band_size"` HipSize *int `db:"hip_size" json:"hip_size"` WaistSize *int `db:"waist_size" json:"waist_size"` BreastType *models.BreastTypeEnum `db:"breast_type" json:"breast_type"` CareerStartYear *int `db:"career_start_year" json:"career_start_year"` CareerEndYear *int `db:"career_end_year" json:"career_end_year"` Deathdate *string `db:"deathdate" json:"deathdate"` } // Performer queries func (q *Queries) CreatePerformer(ctx context.Context, arg CreatePerformerParams) (Performer, error) { row := q.db.QueryRow(ctx, createPerformer, arg.ID, arg.Name, arg.Disambiguation, arg.Gender, arg.Birthdate, arg.Ethnicity, arg.Country, arg.EyeColor, arg.HairColor, arg.Height, arg.CupSize, arg.BandSize, arg.HipSize, arg.WaistSize, arg.BreastType, arg.CareerStartYear, arg.CareerEndYear, arg.Deathdate, ) var i Performer err := row.Scan( &i.ID, &i.Name, &i.Disambiguation, &i.Gender, &i.Ethnicity, &i.Country, &i.EyeColor, &i.HairColor, &i.Height, &i.CupSize, &i.BandSize, &i.HipSize, &i.WaistSize, &i.BreastType, &i.CareerStartYear, &i.CareerEndYear, &i.CreatedAt, &i.UpdatedAt, &i.Deleted, &i.Birthdate, &i.Deathdate, ) return i, err } type CreatePerformerAliasesParams struct { PerformerID uuid.UUID `db:"performer_id" json:"performer_id"` Alias string `db:"alias" json:"alias"` } const createPerformerFavorite = `-- name: CreatePerformerFavorite :exec INSERT INTO performer_favorites (performer_id, user_id, created_at) VALUES ($1, $2, now()) ` type CreatePerformerFavoriteParams struct { PerformerID uuid.UUID `db:"performer_id" json:"performer_id"` UserID uuid.UUID `db:"user_id" json:"user_id"` } func (q *Queries) CreatePerformerFavorite(ctx context.Context, arg CreatePerformerFavoriteParams) error { _, err := q.db.Exec(ctx, createPerformerFavorite, arg.PerformerID, arg.UserID) return err } type CreatePerformerImagesParams struct { PerformerID uuid.UUID `db:"performer_id" json:"performer_id"` ImageID uuid.UUID `db:"image_id" json:"image_id"` } type CreatePerformerPiercingsParams struct { PerformerID uuid.UUID `db:"performer_id" json:"performer_id"` Location *string `db:"location" json:"location"` Description *string `db:"description" json:"description"` } const createPerformerRedirect = `-- name: CreatePerformerRedirect :exec INSERT INTO performer_redirects (source_id, target_id) VALUES ($1, $2) ` type CreatePerformerRedirectParams struct { SourceID uuid.UUID `db:"source_id" json:"source_id"` TargetID uuid.UUID `db:"target_id" json:"target_id"` } // Performer redirects func (q *Queries) CreatePerformerRedirect(ctx context.Context, arg CreatePerformerRedirectParams) error { _, err := q.db.Exec(ctx, createPerformerRedirect, arg.SourceID, arg.TargetID) return err } type CreatePerformerTattoosParams struct { PerformerID uuid.UUID `db:"performer_id" json:"performer_id"` Location *string `db:"location" json:"location"` Description *string `db:"description" json:"description"` } type CreatePerformerURLsParams struct { PerformerID uuid.UUID `db:"performer_id" json:"performer_id"` Url string `db:"url" json:"url"` SiteID uuid.UUID `db:"site_id" json:"site_id"` } const deletePerformer = `-- name: DeletePerformer :exec DELETE FROM performers WHERE id = $1 ` func (q *Queries) DeletePerformer(ctx context.Context, id uuid.UUID) error { _, err := q.db.Exec(ctx, deletePerformer, id) return err } const deletePerformerAliases = `-- name: DeletePerformerAliases :exec DELETE FROM performer_aliases WHERE performer_id = $1 ` // Performer aliases func (q *Queries) DeletePerformerAliases(ctx context.Context, performerID uuid.UUID) error { _, err := q.db.Exec(ctx, deletePerformerAliases, performerID) return err } const deletePerformerFavorite = `-- name: DeletePerformerFavorite :exec DELETE FROM performer_favorites WHERE performer_id = $1 AND user_id = $2 ` type DeletePerformerFavoriteParams struct { PerformerID uuid.UUID `db:"performer_id" json:"performer_id"` UserID uuid.UUID `db:"user_id" json:"user_id"` } func (q *Queries) DeletePerformerFavorite(ctx context.Context, arg DeletePerformerFavoriteParams) error { _, err := q.db.Exec(ctx, deletePerformerFavorite, arg.PerformerID, arg.UserID) return err } const deletePerformerFavorites = `-- name: DeletePerformerFavorites :exec DELETE FROM performer_favorites WHERE performer_id = $1 ` // Performer favorites func (q *Queries) DeletePerformerFavorites(ctx context.Context, performerID uuid.UUID) error { _, err := q.db.Exec(ctx, deletePerformerFavorites, performerID) return err } const deletePerformerImages = `-- name: DeletePerformerImages :exec DELETE FROM performer_images WHERE performer_id = $1 ` func (q *Queries) DeletePerformerImages(ctx context.Context, performerID uuid.UUID) error { _, err := q.db.Exec(ctx, deletePerformerImages, performerID) return err } const deletePerformerPiercings = `-- name: DeletePerformerPiercings :exec DELETE FROM performer_piercings WHERE performer_id = $1 ` // Performer piercings func (q *Queries) DeletePerformerPiercings(ctx context.Context, performerID uuid.UUID) error { _, err := q.db.Exec(ctx, deletePerformerPiercings, performerID) return err } const deletePerformerScenes = `-- name: DeletePerformerScenes :exec DELETE FROM scene_performers WHERE performer_id = $1 ` func (q *Queries) DeletePerformerScenes(ctx context.Context, performerID uuid.UUID) error { _, err := q.db.Exec(ctx, deletePerformerScenes, performerID) return err } const deletePerformerTattoos = `-- name: DeletePerformerTattoos :exec DELETE FROM performer_tattoos WHERE performer_id = $1 ` // Performer tattoos func (q *Queries) DeletePerformerTattoos(ctx context.Context, performerID uuid.UUID) error { _, err := q.db.Exec(ctx, deletePerformerTattoos, performerID) return err } const deletePerformerURLs = `-- name: DeletePerformerURLs :exec DELETE FROM performer_urls WHERE performer_id = $1 ` // Performer URLs func (q *Queries) DeletePerformerURLs(ctx context.Context, performerID uuid.UUID) error { _, err := q.db.Exec(ctx, deletePerformerURLs, performerID) return err } const findExistingPerformers = `-- name: FindExistingPerformers :many SELECT id, name, disambiguation, gender, ethnicity, country, eye_color, hair_color, height, cup_size, band_size, hip_size, waist_size, breast_type, career_start_year, career_end_year, created_at, updated_at, deleted, birthdate, deathdate FROM performers WHERE ( ($1::text IS NOT NULL AND TRIM(LOWER(name)) = TRIM(LOWER($1)) AND CASE WHEN $2::text IS NOT NULL THEN TRIM(LOWER(disambiguation)) = TRIM(LOWER($2)) ELSE (disambiguation IS NULL OR disambiguation = '') END) OR ($3::text[] IS NOT NULL AND id IN ( SELECT performer_id FROM performer_urls WHERE url = ANY($3) GROUP BY performer_id )) ) ` type FindExistingPerformersParams struct { Name *string `db:"name" json:"name"` Disambiguation *string `db:"disambiguation" json:"disambiguation"` Urls []string `db:"urls" json:"urls"` } func (q *Queries) FindExistingPerformers(ctx context.Context, arg FindExistingPerformersParams) ([]Performer, error) { rows, err := q.db.Query(ctx, findExistingPerformers, arg.Name, arg.Disambiguation, arg.Urls) if err != nil { return nil, err } defer rows.Close() items := []Performer{} for rows.Next() { var i Performer if err := rows.Scan( &i.ID, &i.Name, &i.Disambiguation, &i.Gender, &i.Ethnicity, &i.Country, &i.EyeColor, &i.HairColor, &i.Height, &i.CupSize, &i.BandSize, &i.HipSize, &i.WaistSize, &i.BreastType, &i.CareerStartYear, &i.CareerEndYear, &i.CreatedAt, &i.UpdatedAt, &i.Deleted, &i.Birthdate, &i.Deathdate, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const findMergeIDsByPerformerIds = `-- name: FindMergeIDsByPerformerIds :many SELECT source_id as performer_id, target_id as merge_id FROM performer_redirects WHERE source_id = ANY($1::UUID[]) ` type FindMergeIDsByPerformerIdsRow struct { PerformerID uuid.UUID `db:"performer_id" json:"performer_id"` MergeID uuid.UUID `db:"merge_id" json:"merge_id"` } // Find merge target IDs for performers (for merges where these are sources) func (q *Queries) FindMergeIDsByPerformerIds(ctx context.Context, performerIds []uuid.UUID) ([]FindMergeIDsByPerformerIdsRow, error) { rows, err := q.db.Query(ctx, findMergeIDsByPerformerIds, performerIds) if err != nil { return nil, err } defer rows.Close() items := []FindMergeIDsByPerformerIdsRow{} for rows.Next() { var i FindMergeIDsByPerformerIdsRow if err := rows.Scan(&i.PerformerID, &i.MergeID); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const findMergeIDsBySourcePerformerIds = `-- name: FindMergeIDsBySourcePerformerIds :many SELECT target_id as performer_id, source_id as merge_id FROM performer_redirects WHERE target_id = ANY($1::UUID[]) ` type FindMergeIDsBySourcePerformerIdsRow struct { PerformerID uuid.UUID `db:"performer_id" json:"performer_id"` MergeID uuid.UUID `db:"merge_id" json:"merge_id"` } // Find merge source IDs for performers (for merges where these are targets) func (q *Queries) FindMergeIDsBySourcePerformerIds(ctx context.Context, performerIds []uuid.UUID) ([]FindMergeIDsBySourcePerformerIdsRow, error) { rows, err := q.db.Query(ctx, findMergeIDsBySourcePerformerIds, performerIds) if err != nil { return nil, err } defer rows.Close() items := []FindMergeIDsBySourcePerformerIdsRow{} for rows.Next() { var i FindMergeIDsBySourcePerformerIdsRow if err := rows.Scan(&i.PerformerID, &i.MergeID); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const findPerformer = `-- name: FindPerformer :one SELECT id, name, disambiguation, gender, ethnicity, country, eye_color, hair_color, height, cup_size, band_size, hip_size, waist_size, breast_type, career_start_year, career_end_year, created_at, updated_at, deleted, birthdate, deathdate FROM performers WHERE id = $1 ` func (q *Queries) FindPerformer(ctx context.Context, id uuid.UUID) (Performer, error) { row := q.db.QueryRow(ctx, findPerformer, id) var i Performer err := row.Scan( &i.ID, &i.Name, &i.Disambiguation, &i.Gender, &i.Ethnicity, &i.Country, &i.EyeColor, &i.HairColor, &i.Height, &i.CupSize, &i.BandSize, &i.HipSize, &i.WaistSize, &i.BreastType, &i.CareerStartYear, &i.CareerEndYear, &i.CreatedAt, &i.UpdatedAt, &i.Deleted, &i.Birthdate, &i.Deathdate, ) return i, err } const findPerformerAliasesByIds = `-- name: FindPerformerAliasesByIds :many SELECT performer_id, alias FROM performer_aliases WHERE performer_id = ANY($1::UUID[]) ` // Get aliases for multiple performers func (q *Queries) FindPerformerAliasesByIds(ctx context.Context, performerIds []uuid.UUID) ([]PerformerAlias, error) { rows, err := q.db.Query(ctx, findPerformerAliasesByIds, performerIds) if err != nil { return nil, err } defer rows.Close() items := []PerformerAlias{} for rows.Next() { var i PerformerAlias if err := rows.Scan(&i.PerformerID, &i.Alias); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const findPerformerByAlias = `-- name: FindPerformerByAlias :one SELECT p.id, p.name, p.disambiguation, p.gender, p.ethnicity, p.country, p.eye_color, p.hair_color, p.height, p.cup_size, p.band_size, p.hip_size, p.waist_size, p.breast_type, p.career_start_year, p.career_end_year, p.created_at, p.updated_at, p.deleted, p.birthdate, p.deathdate FROM performers p JOIN performer_aliases pa ON p.id = pa.performer_id WHERE UPPER(pa.alias) = UPPER($1) AND p.deleted = false ` func (q *Queries) FindPerformerByAlias(ctx context.Context, upper interface{}) (Performer, error) { row := q.db.QueryRow(ctx, findPerformerByAlias, upper) var i Performer err := row.Scan( &i.ID, &i.Name, &i.Disambiguation, &i.Gender, &i.Ethnicity, &i.Country, &i.EyeColor, &i.HairColor, &i.Height, &i.CupSize, &i.BandSize, &i.HipSize, &i.WaistSize, &i.BreastType, &i.CareerStartYear, &i.CareerEndYear, &i.CreatedAt, &i.UpdatedAt, &i.Deleted, &i.Birthdate, &i.Deathdate, ) return i, err } const findPerformerByName = `-- name: FindPerformerByName :one SELECT id, name, disambiguation, gender, ethnicity, country, eye_color, hair_color, height, cup_size, band_size, hip_size, waist_size, breast_type, career_start_year, career_end_year, created_at, updated_at, deleted, birthdate, deathdate FROM performers WHERE UPPER(name) = UPPER($1) AND deleted = false ` func (q *Queries) FindPerformerByName(ctx context.Context, upper interface{}) (Performer, error) { row := q.db.QueryRow(ctx, findPerformerByName, upper) var i Performer err := row.Scan( &i.ID, &i.Name, &i.Disambiguation, &i.Gender, &i.Ethnicity, &i.Country, &i.EyeColor, &i.HairColor, &i.Height, &i.CupSize, &i.BandSize, &i.HipSize, &i.WaistSize, &i.BreastType, &i.CareerStartYear, &i.CareerEndYear, &i.CreatedAt, &i.UpdatedAt, &i.Deleted, &i.Birthdate, &i.Deathdate, ) return i, err } const findPerformerFavoritesByIds = `-- name: FindPerformerFavoritesByIds :many SELECT performer_id, (performer_id IS NOT NULL)::BOOLEAN as is_favorite FROM performer_favorites WHERE performer_id = ANY($1::UUID[]) AND user_id = $2 ` type FindPerformerFavoritesByIdsParams struct { PerformerIds []uuid.UUID `db:"performer_ids" json:"performer_ids"` UserID uuid.UUID `db:"user_id" json:"user_id"` } type FindPerformerFavoritesByIdsRow struct { PerformerID uuid.UUID `db:"performer_id" json:"performer_id"` IsFavorite bool `db:"is_favorite" json:"is_favorite"` } // Check favorite status for multiple performers for a specific user func (q *Queries) FindPerformerFavoritesByIds(ctx context.Context, arg FindPerformerFavoritesByIdsParams) ([]FindPerformerFavoritesByIdsRow, error) { rows, err := q.db.Query(ctx, findPerformerFavoritesByIds, arg.PerformerIds, arg.UserID) if err != nil { return nil, err } defer rows.Close() items := []FindPerformerFavoritesByIdsRow{} for rows.Next() { var i FindPerformerFavoritesByIdsRow if err := rows.Scan(&i.PerformerID, &i.IsFavorite); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const findPerformerPiercingsByIds = `-- name: FindPerformerPiercingsByIds :many SELECT performer_id, location, description FROM performer_piercings WHERE performer_id = ANY($1::UUID[]) ` // Get piercings for multiple performers func (q *Queries) FindPerformerPiercingsByIds(ctx context.Context, performerIds []uuid.UUID) ([]PerformerPiercing, error) { rows, err := q.db.Query(ctx, findPerformerPiercingsByIds, performerIds) if err != nil { return nil, err } defer rows.Close() items := []PerformerPiercing{} for rows.Next() { var i PerformerPiercing if err := rows.Scan(&i.PerformerID, &i.Location, &i.Description); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const findPerformerTattoosByIds = `-- name: FindPerformerTattoosByIds :many SELECT performer_id, location, description FROM performer_tattoos WHERE performer_id = ANY($1::UUID[]) ` // Get tattoos for multiple performers func (q *Queries) FindPerformerTattoosByIds(ctx context.Context, performerIds []uuid.UUID) ([]PerformerTattoo, error) { rows, err := q.db.Query(ctx, findPerformerTattoosByIds, performerIds) if err != nil { return nil, err } defer rows.Close() items := []PerformerTattoo{} for rows.Next() { var i PerformerTattoo if err := rows.Scan(&i.PerformerID, &i.Location, &i.Description); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const findPerformerUrlsByIds = `-- name: FindPerformerUrlsByIds :many SELECT performer_id, url, site_id FROM performer_urls WHERE performer_id = ANY($1::UUID[]) ` // Get URLs for multiple performers func (q *Queries) FindPerformerUrlsByIds(ctx context.Context, performerIds []uuid.UUID) ([]PerformerUrl, error) { rows, err := q.db.Query(ctx, findPerformerUrlsByIds, performerIds) if err != nil { return nil, err } defer rows.Close() items := []PerformerUrl{} for rows.Next() { var i PerformerUrl if err := rows.Scan(&i.PerformerID, &i.Url, &i.SiteID); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const findPerformerWithRedirect = `-- name: FindPerformerWithRedirect :many SELECT p.id, p.name, p.disambiguation, p.gender, p.ethnicity, p.country, p.eye_color, p.hair_color, p.height, p.cup_size, p.band_size, p.hip_size, p.waist_size, p.breast_type, p.career_start_year, p.career_end_year, p.created_at, p.updated_at, p.deleted, p.birthdate, p.deathdate FROM performers P WHERE P.id = $1 AND P.deleted = FALSE UNION SELECT t.id, t.name, t.disambiguation, t.gender, t.ethnicity, t.country, t.eye_color, t.hair_color, t.height, t.cup_size, t.band_size, t.hip_size, t.waist_size, t.breast_type, t.career_start_year, t.career_end_year, t.created_at, t.updated_at, t.deleted, t.birthdate, t.deathdate FROM performer_redirects R JOIN performers T ON T.id = R.target_id WHERE R.source_id = $1 AND T.deleted = FALSE ` func (q *Queries) FindPerformerWithRedirect(ctx context.Context, id uuid.UUID) ([]Performer, error) { rows, err := q.db.Query(ctx, findPerformerWithRedirect, id) if err != nil { return nil, err } defer rows.Close() items := []Performer{} for rows.Next() { var i Performer if err := rows.Scan( &i.ID, &i.Name, &i.Disambiguation, &i.Gender, &i.Ethnicity, &i.Country, &i.EyeColor, &i.HairColor, &i.Height, &i.CupSize, &i.BandSize, &i.HipSize, &i.WaistSize, &i.BreastType, &i.CareerStartYear, &i.CareerEndYear, &i.CreatedAt, &i.UpdatedAt, &i.Deleted, &i.Birthdate, &i.Deathdate, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const findPerformersByIds = `-- name: FindPerformersByIds :many SELECT id, name, disambiguation, gender, ethnicity, country, eye_color, hair_color, height, cup_size, band_size, hip_size, waist_size, breast_type, career_start_year, career_end_year, created_at, updated_at, deleted, birthdate, deathdate FROM performers WHERE id = ANY($1::UUID[]) ` func (q *Queries) FindPerformersByIds(ctx context.Context, dollar_1 []uuid.UUID) ([]Performer, error) { rows, err := q.db.Query(ctx, findPerformersByIds, dollar_1) if err != nil { return nil, err } defer rows.Close() items := []Performer{} for rows.Next() { var i Performer if err := rows.Scan( &i.ID, &i.Name, &i.Disambiguation, &i.Gender, &i.Ethnicity, &i.Country, &i.EyeColor, &i.HairColor, &i.Height, &i.CupSize, &i.BandSize, &i.HipSize, &i.WaistSize, &i.BreastType, &i.CareerStartYear, &i.CareerEndYear, &i.CreatedAt, &i.UpdatedAt, &i.Deleted, &i.Birthdate, &i.Deathdate, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const findPerformersByURL = `-- name: FindPerformersByURL :many SELECT p.id, p.name, p.disambiguation, p.gender, p.ethnicity, p.country, p.eye_color, p.hair_color, p.height, p.cup_size, p.band_size, p.hip_size, p.waist_size, p.breast_type, p.career_start_year, p.career_end_year, p.created_at, p.updated_at, p.deleted, p.birthdate, p.deathdate FROM performers P JOIN performer_urls PU ON PU.performer_id = P.id WHERE LOWER(PU.url) = LOWER($1) LIMIT $2 ` type FindPerformersByURLParams struct { Url *string `db:"url" json:"url"` Limit int32 `db:"limit" json:"limit"` } func (q *Queries) FindPerformersByURL(ctx context.Context, arg FindPerformersByURLParams) ([]Performer, error) { rows, err := q.db.Query(ctx, findPerformersByURL, arg.Url, arg.Limit) if err != nil { return nil, err } defer rows.Close() items := []Performer{} for rows.Next() { var i Performer if err := rows.Scan( &i.ID, &i.Name, &i.Disambiguation, &i.Gender, &i.Ethnicity, &i.Country, &i.EyeColor, &i.HairColor, &i.Height, &i.CupSize, &i.BandSize, &i.HipSize, &i.WaistSize, &i.BreastType, &i.CareerStartYear, &i.CareerEndYear, &i.CreatedAt, &i.UpdatedAt, &i.Deleted, &i.Birthdate, &i.Deathdate, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getPerformerAliases = `-- name: GetPerformerAliases :many SELECT alias FROM performer_aliases WHERE performer_id = $1 ` func (q *Queries) GetPerformerAliases(ctx context.Context, performerID uuid.UUID) ([]string, error) { rows, err := q.db.Query(ctx, getPerformerAliases, performerID) if err != nil { return nil, err } defer rows.Close() items := []string{} for rows.Next() { var alias string if err := rows.Scan(&alias); err != nil { return nil, err } items = append(items, alias) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getPerformerImages = `-- name: GetPerformerImages :many SELECT images.id, images.url, images.width, images.height, images.checksum FROM images JOIN performer_images ON performer_images.image_id = images.id WHERE performer_images.performer_id = $1 ` // Performer images func (q *Queries) GetPerformerImages(ctx context.Context, performerID uuid.UUID) ([]Image, error) { rows, err := q.db.Query(ctx, getPerformerImages, performerID) if err != nil { return nil, err } defer rows.Close() items := []Image{} for rows.Next() { var i Image if err := rows.Scan( &i.ID, &i.Url, &i.Width, &i.Height, &i.Checksum, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getPerformerPiercings = `-- name: GetPerformerPiercings :many SELECT location, description FROM performer_piercings WHERE performer_id = $1 ` type GetPerformerPiercingsRow struct { Location *string `db:"location" json:"location"` Description *string `db:"description" json:"description"` } func (q *Queries) GetPerformerPiercings(ctx context.Context, performerID uuid.UUID) ([]GetPerformerPiercingsRow, error) { rows, err := q.db.Query(ctx, getPerformerPiercings, performerID) if err != nil { return nil, err } defer rows.Close() items := []GetPerformerPiercingsRow{} for rows.Next() { var i GetPerformerPiercingsRow if err := rows.Scan(&i.Location, &i.Description); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getPerformerTattoos = `-- name: GetPerformerTattoos :many SELECT location, description FROM performer_tattoos WHERE performer_id = $1 ` type GetPerformerTattoosRow struct { Location *string `db:"location" json:"location"` Description *string `db:"description" json:"description"` } func (q *Queries) GetPerformerTattoos(ctx context.Context, performerID uuid.UUID) ([]GetPerformerTattoosRow, error) { rows, err := q.db.Query(ctx, getPerformerTattoos, performerID) if err != nil { return nil, err } defer rows.Close() items := []GetPerformerTattoosRow{} for rows.Next() { var i GetPerformerTattoosRow if err := rows.Scan(&i.Location, &i.Description); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getPerformerURLs = `-- name: GetPerformerURLs :many SELECT url, site_id FROM performer_urls WHERE performer_id = $1 ` type GetPerformerURLsRow struct { Url string `db:"url" json:"url"` SiteID uuid.UUID `db:"site_id" json:"site_id"` } func (q *Queries) GetPerformerURLs(ctx context.Context, performerID uuid.UUID) ([]GetPerformerURLsRow, error) { rows, err := q.db.Query(ctx, getPerformerURLs, performerID) if err != nil { return nil, err } defer rows.Close() items := []GetPerformerURLsRow{} for rows.Next() { var i GetPerformerURLsRow if err := rows.Scan(&i.Url, &i.SiteID); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const reassignPerformerAliases = `-- name: ReassignPerformerAliases :exec UPDATE scene_performers SET performer_id = $1 WHERE scene_performers.performer_id = $2 AND scene_id NOT IN (SELECT scene_id from scene_performers sp WHERE sp.performer_id = $1) ` type ReassignPerformerAliasesParams struct { NewPerformerID uuid.UUID `db:"new_performer_id" json:"new_performer_id"` OldPerformerID uuid.UUID `db:"old_performer_id" json:"old_performer_id"` } func (q *Queries) ReassignPerformerAliases(ctx context.Context, arg ReassignPerformerAliasesParams) error { _, err := q.db.Exec(ctx, reassignPerformerAliases, arg.NewPerformerID, arg.OldPerformerID) return err } const reassignPerformerFavorites = `-- name: ReassignPerformerFavorites :exec UPDATE performer_favorites SET performer_id = $1 WHERE performer_favorites.performer_id = $2 AND user_id NOT IN ( SELECT user_id FROM performer_favorites PF WHERE PF.performer_id = $1 ) ` type ReassignPerformerFavoritesParams struct { NewPerformerID uuid.UUID `db:"new_performer_id" json:"new_performer_id"` OldPerformerID uuid.UUID `db:"old_performer_id" json:"old_performer_id"` } func (q *Queries) ReassignPerformerFavorites(ctx context.Context, arg ReassignPerformerFavoritesParams) error { _, err := q.db.Exec(ctx, reassignPerformerFavorites, arg.NewPerformerID, arg.OldPerformerID) return err } const searchPerformersWithFacets = `-- name: SearchPerformersWithFacets :many SELECT performer_id, pdb.agg('{"terms": {"field": "gender"}}') OVER () as gender_facets, pdb.agg('{"value_count": {"field": "performer_id"}}') OVER () as total_count FROM performer_search WHERE performer_id @@@ paradedb.disjunction_max(disjuncts => ARRAY[ paradedb.boolean( should => ARRAY[ paradedb.boost(factor => 1.5, query => paradedb.match(field => 'name', value => $1::TEXT)), paradedb.match(field => 'disambiguation', value => $1::TEXT) ] ), paradedb.match(field => 'aliases', value => $1::TEXT) ]) AND ($2::TEXT IS NULL OR gender = $2::TEXT) ORDER BY pdb.score(performer_id) DESC LIMIT $4 OFFSET $3 ` type SearchPerformersWithFacetsParams struct { Term *string `db:"term" json:"term"` FilterGender *string `db:"filter_gender" json:"filter_gender"` Offset int32 `db:"offset" json:"offset"` Limit int32 `db:"limit" json:"limit"` } type SearchPerformersWithFacetsRow struct { PerformerID uuid.UUID `db:"performer_id" json:"performer_id"` GenderFacets interface{} `db:"gender_facets" json:"gender_facets"` TotalCount interface{} `db:"total_count" json:"total_count"` } func (q *Queries) SearchPerformersWithFacets(ctx context.Context, arg SearchPerformersWithFacetsParams) ([]SearchPerformersWithFacetsRow, error) { rows, err := q.db.Query(ctx, searchPerformersWithFacets, arg.Term, arg.FilterGender, arg.Offset, arg.Limit, ) if err != nil { return nil, err } defer rows.Close() items := []SearchPerformersWithFacetsRow{} for rows.Next() { var i SearchPerformersWithFacetsRow if err := rows.Scan(&i.PerformerID, &i.GenderFacets, &i.TotalCount); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const setScenePerformerAlias = `-- name: SetScenePerformerAlias :exec UPDATE scene_performers SET "as" = $2 WHERE performer_id = $1 AND "as" IS NULL ` type SetScenePerformerAliasParams struct { PerformerID uuid.UUID `db:"performer_id" json:"performer_id"` As *string `db:"as" json:"as"` } func (q *Queries) SetScenePerformerAlias(ctx context.Context, arg SetScenePerformerAliasParams) error { _, err := q.db.Exec(ctx, setScenePerformerAlias, arg.PerformerID, arg.As) return err } const softDeletePerformer = `-- name: SoftDeletePerformer :one UPDATE performers SET deleted = true, updated_at = NOW() WHERE id = $1 RETURNING id, name, disambiguation, gender, ethnicity, country, eye_color, hair_color, height, cup_size, band_size, hip_size, waist_size, breast_type, career_start_year, career_end_year, created_at, updated_at, deleted, birthdate, deathdate ` func (q *Queries) SoftDeletePerformer(ctx context.Context, id uuid.UUID) (Performer, error) { row := q.db.QueryRow(ctx, softDeletePerformer, id) var i Performer err := row.Scan( &i.ID, &i.Name, &i.Disambiguation, &i.Gender, &i.Ethnicity, &i.Country, &i.EyeColor, &i.HairColor, &i.Height, &i.CupSize, &i.BandSize, &i.HipSize, &i.WaistSize, &i.BreastType, &i.CareerStartYear, &i.CareerEndYear, &i.CreatedAt, &i.UpdatedAt, &i.Deleted, &i.Birthdate, &i.Deathdate, ) return i, err } const updatePerformer = `-- name: UpdatePerformer :one UPDATE performers SET name = $2, disambiguation = $3, gender = $4, birthdate = $5, ethnicity = $6, country = $7, eye_color = $8, hair_color = $9, height = $10, cup_size = $11, band_size = $12, hip_size = $13, waist_size = $14, breast_type = $15, career_start_year = $16, career_end_year = $17, deathdate = $18, updated_at = now() WHERE id = $1 RETURNING id, name, disambiguation, gender, ethnicity, country, eye_color, hair_color, height, cup_size, band_size, hip_size, waist_size, breast_type, career_start_year, career_end_year, created_at, updated_at, deleted, birthdate, deathdate ` type UpdatePerformerParams struct { ID uuid.UUID `db:"id" json:"id"` Name string `db:"name" json:"name"` Disambiguation *string `db:"disambiguation" json:"disambiguation"` Gender *models.GenderEnum `db:"gender" json:"gender"` Birthdate *string `db:"birthdate" json:"birthdate"` Ethnicity *models.EthnicityEnum `db:"ethnicity" json:"ethnicity"` Country *string `db:"country" json:"country"` EyeColor *models.EyeColorEnum `db:"eye_color" json:"eye_color"` HairColor *models.HairColorEnum `db:"hair_color" json:"hair_color"` Height *int `db:"height" json:"height"` CupSize *string `db:"cup_size" json:"cup_size"` BandSize *int `db:"band_size" json:"band_size"` HipSize *int `db:"hip_size" json:"hip_size"` WaistSize *int `db:"waist_size" json:"waist_size"` BreastType *models.BreastTypeEnum `db:"breast_type" json:"breast_type"` CareerStartYear *int `db:"career_start_year" json:"career_start_year"` CareerEndYear *int `db:"career_end_year" json:"career_end_year"` Deathdate *string `db:"deathdate" json:"deathdate"` } func (q *Queries) UpdatePerformer(ctx context.Context, arg UpdatePerformerParams) (Performer, error) { row := q.db.QueryRow(ctx, updatePerformer, arg.ID, arg.Name, arg.Disambiguation, arg.Gender, arg.Birthdate, arg.Ethnicity, arg.Country, arg.EyeColor, arg.HairColor, arg.Height, arg.CupSize, arg.BandSize, arg.HipSize, arg.WaistSize, arg.BreastType, arg.CareerStartYear, arg.CareerEndYear, arg.Deathdate, ) var i Performer err := row.Scan( &i.ID, &i.Name, &i.Disambiguation, &i.Gender, &i.Ethnicity, &i.Country, &i.EyeColor, &i.HairColor, &i.Height, &i.CupSize, &i.BandSize, &i.HipSize, &i.WaistSize, &i.BreastType, &i.CareerStartYear, &i.CareerEndYear, &i.CreatedAt, &i.UpdatedAt, &i.Deleted, &i.Birthdate, &i.Deathdate, ) return i, err } const updatePerformerRedirects = `-- name: UpdatePerformerRedirects :exec UPDATE performer_redirects SET target_id = $1 WHERE target_id = $2 ` type UpdatePerformerRedirectsParams struct { NewPerformerID uuid.UUID `db:"new_performer_id" json:"new_performer_id"` OldPerformerID uuid.UUID `db:"old_performer_id" json:"old_performer_id"` } func (q *Queries) UpdatePerformerRedirects(ctx context.Context, arg UpdatePerformerRedirectsParams) error { _, err := q.db.Exec(ctx, updatePerformerRedirects, arg.NewPerformerID, arg.OldPerformerID) return err } ================================================ FILE: internal/queries/querier.go ================================================ // Code generated by sqlc. DO NOT EDIT. // versions: // sqlc v1.29.0 package queries import ( "context" "github.com/gofrs/uuid" ) type Querier interface { CancelUserEdits(ctx context.Context, userID uuid.NullUUID) error ClearScenePerformerAlias(ctx context.Context, arg ClearScenePerformerAliasParams) error CountNotificationsByUser(ctx context.Context, arg CountNotificationsByUserParams) (int64, error) CountScenesByPerformer(ctx context.Context, performerID uuid.UUID) (int64, error) CountUserEditsByStatus(ctx context.Context, userID uuid.NullUUID) ([]CountUserEditsByStatusRow, error) CountUsers(ctx context.Context) (int64, error) CountVotesByType(ctx context.Context, userID uuid.UUID) ([]CountVotesByTypeRow, error) // Draft queries CreateDraft(ctx context.Context, arg CreateDraftParams) (Draft, error) // Edit queries CreateEdit(ctx context.Context, arg CreateEditParams) (Edit, error) // Edit comments CreateEditComment(ctx context.Context, arg CreateEditCommentParams) (EditComment, error) // Edit votes CreateEditVote(ctx context.Context, arg CreateEditVoteParams) error // Fingerprint queries (normalized schema) CreateFingerprint(ctx context.Context, arg CreateFingerprintParams) (Fingerprint, error) // Image queries CreateImage(ctx context.Context, arg CreateImageParams) (Image, error) // Invite key queries CreateInviteKey(ctx context.Context, arg CreateInviteKeyParams) (InviteKey, error) CreateModAudit(ctx context.Context, arg CreateModAuditParams) (ModAudit, error) CreateOrReplaceFingerprint(ctx context.Context, arg CreateOrReplaceFingerprintParams) error // Performer queries CreatePerformer(ctx context.Context, arg CreatePerformerParams) (Performer, error) CreatePerformerAliases(ctx context.Context, arg []CreatePerformerAliasesParams) (int64, error) CreatePerformerEdit(ctx context.Context, arg CreatePerformerEditParams) error CreatePerformerFavorite(ctx context.Context, arg CreatePerformerFavoriteParams) error CreatePerformerImages(ctx context.Context, arg []CreatePerformerImagesParams) (int64, error) CreatePerformerPiercings(ctx context.Context, arg []CreatePerformerPiercingsParams) (int64, error) // Performer redirects CreatePerformerRedirect(ctx context.Context, arg CreatePerformerRedirectParams) error CreatePerformerTattoos(ctx context.Context, arg []CreatePerformerTattoosParams) (int64, error) CreatePerformerURLs(ctx context.Context, arg []CreatePerformerURLsParams) (int64, error) // Scene queries CreateScene(ctx context.Context, arg CreateSceneParams) (Scene, error) CreateSceneEdit(ctx context.Context, arg CreateSceneEditParams) error CreateSceneFingerprints(ctx context.Context, arg []CreateSceneFingerprintsParams) (int64, error) CreateSceneImages(ctx context.Context, arg []CreateSceneImagesParams) (int64, error) // Scene performers CreateScenePerformers(ctx context.Context, arg []CreateScenePerformersParams) (int64, error) // Scene redirects CreateSceneRedirect(ctx context.Context, arg CreateSceneRedirectParams) error // Scene tags management CreateSceneTags(ctx context.Context, arg []CreateSceneTagsParams) (int64, error) // Scene URLs CreateSceneURLs(ctx context.Context, arg []CreateSceneURLsParams) (int64, error) // Site queries CreateSite(ctx context.Context, arg CreateSiteParams) (Site, error) // Studio queries CreateStudio(ctx context.Context, arg CreateStudioParams) (Studio, error) // Studio aliases CreateStudioAliases(ctx context.Context, arg []CreateStudioAliasesParams) (int64, error) CreateStudioEdit(ctx context.Context, arg CreateStudioEditParams) error // Studio favorites CreateStudioFavorite(ctx context.Context, arg CreateStudioFavoriteParams) error // Studio images CreateStudioImages(ctx context.Context, arg []CreateStudioImagesParams) (int64, error) // Studio redirects CreateStudioRedirect(ctx context.Context, arg CreateStudioRedirectParams) error // Studio URLs CreateStudioURLs(ctx context.Context, arg []CreateStudioURLsParams) (int64, error) // Tag queries CreateTag(ctx context.Context, arg CreateTagParams) (Tag, error) // Tag aliases CreateTagAliases(ctx context.Context, arg []CreateTagAliasesParams) (int64, error) // Tag category queries CreateTagCategory(ctx context.Context, arg CreateTagCategoryParams) (TagCategory, error) CreateTagEdit(ctx context.Context, arg CreateTagEditParams) error // Tag redirects CreateTagRedirect(ctx context.Context, arg CreateTagRedirectParams) error // User queries CreateUser(ctx context.Context, arg CreateUserParams) (User, error) // User notification subscriptions CreateUserNotificationSubscriptions(ctx context.Context, arg []CreateUserNotificationSubscriptionsParams) (int64, error) // User roles CreateUserRoles(ctx context.Context, arg []CreateUserRolesParams) (int64, error) // User token queries CreateUserToken(ctx context.Context, arg CreateUserTokenParams) (UserToken, error) DeleteAllSceneFingerprintSubmissions(ctx context.Context, arg DeleteAllSceneFingerprintSubmissionsParams) (int64, error) DeleteDraft(ctx context.Context, id uuid.UUID) error DeleteEdit(ctx context.Context, id uuid.UUID) error DeleteExpiredDrafts(ctx context.Context, dollar_1 interface{}) error DeleteExpiredModAudits(ctx context.Context, dollar_1 interface{}) error DeleteExpiredUserTokens(ctx context.Context) error DeleteImage(ctx context.Context, id uuid.UUID) error DeleteInviteKey(ctx context.Context, id uuid.UUID) error DeletePerformer(ctx context.Context, id uuid.UUID) error // Performer aliases DeletePerformerAliases(ctx context.Context, performerID uuid.UUID) error DeletePerformerFavorite(ctx context.Context, arg DeletePerformerFavoriteParams) error // Performer favorites DeletePerformerFavorites(ctx context.Context, performerID uuid.UUID) error DeletePerformerImages(ctx context.Context, performerID uuid.UUID) error // Performer piercings DeletePerformerPiercings(ctx context.Context, performerID uuid.UUID) error DeletePerformerScenes(ctx context.Context, performerID uuid.UUID) error // Performer tattoos DeletePerformerTattoos(ctx context.Context, performerID uuid.UUID) error // Performer URLs DeletePerformerURLs(ctx context.Context, performerID uuid.UUID) error DeleteScene(ctx context.Context, id uuid.UUID) error DeleteSceneFingerprint(ctx context.Context, arg DeleteSceneFingerprintParams) error DeleteSceneFingerprintsByScene(ctx context.Context, sceneID uuid.UUID) error // Scene images DeleteSceneImages(ctx context.Context, sceneID uuid.UUID) error DeleteScenePerformers(ctx context.Context, sceneID uuid.UUID) error DeleteSceneStudios(ctx context.Context, studioID uuid.NullUUID) error DeleteSceneTagsByScene(ctx context.Context, sceneID uuid.UUID) error DeleteSceneTagsByTag(ctx context.Context, tagID uuid.UUID) error DeleteSceneURLs(ctx context.Context, sceneID uuid.UUID) error DeleteSite(ctx context.Context, id uuid.UUID) error DeleteStudio(ctx context.Context, id uuid.UUID) error DeleteStudioAliases(ctx context.Context, studioID uuid.UUID) error DeleteStudioFavorite(ctx context.Context, arg DeleteStudioFavoriteParams) error DeleteStudioFavorites(ctx context.Context, studioID uuid.UUID) error DeleteStudioImages(ctx context.Context, studioID uuid.UUID) error DeleteStudioURLs(ctx context.Context, studioID uuid.UUID) error DeleteTag(ctx context.Context, id uuid.UUID) error DeleteTagAliases(ctx context.Context, tagID uuid.UUID) error DeleteTagAliasesByNames(ctx context.Context, arg DeleteTagAliasesByNamesParams) error DeleteTagCategory(ctx context.Context, id uuid.UUID) error DeleteUser(ctx context.Context, id uuid.UUID) error DeleteUserNotificationSubscriptions(ctx context.Context, userID uuid.UUID) error DeleteUserRoles(ctx context.Context, userID uuid.UUID) error DeleteUserToken(ctx context.Context, id uuid.UUID) error DestroyExpiredInvites(ctx context.Context) error DestroyExpiredNotifications(ctx context.Context) error FindActiveInviteKeysForUser(ctx context.Context, generatedBy uuid.UUID) ([]InviteKey, error) // Returns pending edits that fulfill one of the criteria for being closed: // * The full voting period has passed // * The minimum voting period has passed, and the number of votes has crossed the voting threshold. // The latter only applies for destructive edits. Non-destructive edits get auto-applied when sufficient votes are cast. FindCompletedEdits(ctx context.Context, arg FindCompletedEditsParams) ([]Edit, error) FindDraft(ctx context.Context, id uuid.UUID) (Draft, error) FindDraftsByUser(ctx context.Context, userID uuid.UUID) ([]Draft, error) FindEdit(ctx context.Context, id uuid.UUID) (Edit, error) FindExistingPerformers(ctx context.Context, arg FindExistingPerformersParams) ([]Performer, error) FindExistingScenes(ctx context.Context, arg FindExistingScenesParams) ([]Scene, error) FindImage(ctx context.Context, id uuid.UUID) (Image, error) FindImageByChecksum(ctx context.Context, checksum string) (Image, error) FindImageIdsByPerformerIds(ctx context.Context, dollar_1 []uuid.UUID) ([]PerformerImage, error) FindImageIdsBySceneIds(ctx context.Context, dollar_1 []uuid.UUID) ([]SceneImage, error) FindImageIdsByStudioIds(ctx context.Context, dollar_1 []uuid.UUID) ([]StudioImage, error) FindImagesByIds(ctx context.Context, dollar_1 []uuid.UUID) ([]Image, error) FindImagesBySceneID(ctx context.Context, id uuid.UUID) ([]Image, error) FindImagesByStudioID(ctx context.Context, id uuid.UUID) ([]Image, error) FindInviteKey(ctx context.Context, id uuid.UUID) (InviteKey, error) // Find merge target IDs for performers (for merges where these are sources) FindMergeIDsByPerformerIds(ctx context.Context, performerIds []uuid.UUID) ([]FindMergeIDsByPerformerIdsRow, error) // Find merge source IDs for performers (for merges where these are targets) FindMergeIDsBySourcePerformerIds(ctx context.Context, performerIds []uuid.UUID) ([]FindMergeIDsBySourcePerformerIdsRow, error) // Notification queries FindNotificationsByUser(ctx context.Context, arg FindNotificationsByUserParams) ([]Notification, error) FindPendingPerformerCreation(ctx context.Context, arg FindPendingPerformerCreationParams) ([]Edit, error) FindPendingSceneCreation(ctx context.Context, arg FindPendingSceneCreationParams) ([]Edit, error) FindPerformer(ctx context.Context, id uuid.UUID) (Performer, error) // Get aliases for multiple performers FindPerformerAliasesByIds(ctx context.Context, performerIds []uuid.UUID) ([]PerformerAlias, error) FindPerformerByAlias(ctx context.Context, upper interface{}) (Performer, error) FindPerformerByName(ctx context.Context, upper interface{}) (Performer, error) // Check favorite status for multiple performers for a specific user FindPerformerFavoritesByIds(ctx context.Context, arg FindPerformerFavoritesByIdsParams) ([]FindPerformerFavoritesByIdsRow, error) // Get piercings for multiple performers FindPerformerPiercingsByIds(ctx context.Context, performerIds []uuid.UUID) ([]PerformerPiercing, error) // Get tattoos for multiple performers FindPerformerTattoosByIds(ctx context.Context, performerIds []uuid.UUID) ([]PerformerTattoo, error) // Get URLs for multiple performers FindPerformerUrlsByIds(ctx context.Context, performerIds []uuid.UUID) ([]PerformerUrl, error) FindPerformerWithRedirect(ctx context.Context, id uuid.UUID) ([]Performer, error) FindPerformersByIds(ctx context.Context, dollar_1 []uuid.UUID) ([]Performer, error) FindPerformersByURL(ctx context.Context, arg FindPerformersByURLParams) ([]Performer, error) FindScene(ctx context.Context, id uuid.UUID) (Scene, error) // Get performer appearances for multiple scenes FindSceneAppearancesByIds(ctx context.Context, sceneIds []uuid.UUID) ([]FindSceneAppearancesByIdsRow, error) FindSceneByURL(ctx context.Context, arg FindSceneByURLParams) ([]Scene, error) // Get URLs for multiple scenes FindSceneUrlsByIds(ctx context.Context, sceneIds []uuid.UUID) ([]SceneUrl, error) // Scene fingerprints (use fingerprint.sql for most fingerprint operations) FindScenesByFullFingerprintsWithHash(ctx context.Context, arg FindScenesByFullFingerprintsWithHashParams) ([]FindScenesByFullFingerprintsWithHashRow, error) FindSitesByIds(ctx context.Context, dollar_1 []uuid.UUID) ([]Site, error) FindStudio(ctx context.Context, id uuid.UUID) (Studio, error) // Get aliases for multiple studios FindStudioAliasesByIds(ctx context.Context, studioIds []uuid.UUID) ([]StudioAlias, error) FindStudioByAlias(ctx context.Context, upper interface{}) (Studio, error) FindStudioByName(ctx context.Context, upper interface{}) (Studio, error) // Check favorite status for multiple studios for a specific user FindStudioFavoritesByIds(ctx context.Context, arg FindStudioFavoritesByIdsParams) ([]FindStudioFavoritesByIdsRow, error) // Get URLs for multiple studios FindStudioUrlsByIds(ctx context.Context, studioIds []uuid.UUID) ([]StudioUrl, error) FindStudioWithRedirect(ctx context.Context, id uuid.UUID) (Studio, error) FindTag(ctx context.Context, id uuid.UUID) (Tag, error) FindTagByAlias(ctx context.Context, upper interface{}) (Tag, error) FindTagByName(ctx context.Context, upper interface{}) (Tag, error) FindTagByNameOrAlias(ctx context.Context, lower string) (Tag, error) FindTagCategory(ctx context.Context, id uuid.UUID) (TagCategory, error) // Bulk query to find tag IDs for multiple scene IDs FindTagIdsBySceneIds(ctx context.Context, sceneIds []uuid.UUID) ([]SceneTag, error) FindTagWithRedirect(ctx context.Context, id uuid.UUID) ([]Tag, error) FindTagsByIds(ctx context.Context, dollar_1 []uuid.UUID) ([]Tag, error) FindTagsBySceneID(ctx context.Context, sceneID uuid.UUID) ([]Tag, error) FindUnreadNotificationsByUser(ctx context.Context, arg FindUnreadNotificationsByUserParams) ([]Notification, error) FindUnusedImages(ctx context.Context) ([]Image, error) FindUser(ctx context.Context, id uuid.UUID) (User, error) FindUserByEmail(ctx context.Context, upper interface{}) (User, error) FindUserByName(ctx context.Context, name string) (User, error) FindUserToken(ctx context.Context, id uuid.UUID) (UserToken, error) FindUserTokensByEmail(ctx context.Context, dollar_1 string) ([]UserToken, error) FindUserTokensByInviteKey(ctx context.Context, dollar_1 uuid.UUID) ([]UserToken, error) // Get all fingerprints for multiple scenes with aggregated vote data // When onlySubmitted is true, pass the actual user ID, when false pass NULL GetAllFingerprints(ctx context.Context, arg GetAllFingerprintsParams) ([]GetAllFingerprintsRow, error) GetAllSceneFingerprints(ctx context.Context, sceneID uuid.UUID) ([]GetAllSceneFingerprintsRow, error) GetAllTagCategories(ctx context.Context) ([]TagCategory, error) GetChildStudios(ctx context.Context, parentStudioID uuid.NullUUID) ([]Studio, error) GetEditComments(ctx context.Context, editID uuid.UUID) ([]EditComment, error) GetEditCommentsByIds(ctx context.Context, dollar_1 []uuid.UUID) ([]EditComment, error) GetEditPerformerAliases(ctx context.Context, id uuid.UUID) ([]string, error) GetEditPerformerPiercings(ctx context.Context, id uuid.UUID) ([]GetEditPerformerPiercingsRow, error) GetEditPerformerTattoos(ctx context.Context, id uuid.UUID) ([]GetEditPerformerTattoosRow, error) GetEditTargetID(ctx context.Context, id uuid.UUID) (GetEditTargetIDRow, error) GetEditVotes(ctx context.Context, editID uuid.UUID) ([]EditVote, error) GetEditsByIds(ctx context.Context, dollar_1 []uuid.UUID) ([]Edit, error) GetEditsByPerformer(ctx context.Context, performerID uuid.UUID) ([]Edit, error) GetEditsByScene(ctx context.Context, sceneID uuid.UUID) ([]Edit, error) GetEditsByStudio(ctx context.Context, studioID uuid.UUID) ([]Edit, error) GetEditsByTag(ctx context.Context, tagID uuid.UUID) ([]Edit, error) GetFingerprint(ctx context.Context, arg GetFingerprintParams) (Fingerprint, error) // Gets current images for target entity and merges with edit's added_images/removed_images GetImagesForEdit(ctx context.Context, id uuid.UUID) ([]Image, error) // Gets current performers for target entity and merges with edit's added_performers/removed_performers GetMergedPerformersForEdit(ctx context.Context, id uuid.UUID) ([]GetMergedPerformersForEditRow, error) // Gets current aliases for target studio entity and merges with edit's added_aliases/removed_aliases GetMergedStudioAliasesForEdit(ctx context.Context, id uuid.UUID) ([]string, error) // Gets current aliases for target tag entity and merges with edit's added_aliases/removed_aliases GetMergedTagAliasesForEdit(ctx context.Context, id uuid.UUID) ([]string, error) // Gets current tags for target entity and merges with edit's added_tags/removed_tags GetMergedTagsForEdit(ctx context.Context, id uuid.UUID) ([]Tag, error) // URL merging queries for edits // result: URL // Gets current URLs for target entity and merges with edit's added_urls/removed_urls GetMergedURLsForEdit(ctx context.Context, id uuid.UUID) ([]GetMergedURLsForEditRow, error) GetModAuditCount(ctx context.Context, arg GetModAuditCountParams) (int64, error) GetPerformerAliases(ctx context.Context, performerID uuid.UUID) ([]string, error) // Performer images GetPerformerImages(ctx context.Context, performerID uuid.UUID) ([]Image, error) GetPerformerPiercings(ctx context.Context, performerID uuid.UUID) ([]GetPerformerPiercingsRow, error) GetPerformerTattoos(ctx context.Context, performerID uuid.UUID) ([]GetPerformerTattoosRow, error) GetPerformerURLs(ctx context.Context, performerID uuid.UUID) ([]GetPerformerURLsRow, error) GetScenePerformers(ctx context.Context, sceneID uuid.UUID) ([]GetScenePerformersRow, error) GetSceneTags(ctx context.Context, sceneID uuid.UUID) ([]Tag, error) GetSceneURLs(ctx context.Context, sceneID uuid.UUID) ([]GetSceneURLsRow, error) GetScenes(ctx context.Context, dollar_1 []uuid.UUID) ([]Scene, error) GetSite(ctx context.Context, id uuid.UUID) (Site, error) GetStudioAliases(ctx context.Context, studioID uuid.UUID) ([]string, error) GetStudioImages(ctx context.Context, studioID uuid.UUID) ([]uuid.UUID, error) GetStudioURLs(ctx context.Context, studioID uuid.UUID) ([]StudioUrl, error) GetStudios(ctx context.Context, dollar_1 []uuid.UUID) ([]Studio, error) GetStudiosByPerformer(ctx context.Context, performerID uuid.UUID) ([]GetStudiosByPerformerRow, error) // Get studios where performer has scenes, filtered to a studio network (the studio, its parent, and children) GetStudiosByPerformerAndNetwork(ctx context.Context, arg GetStudiosByPerformerAndNetworkParams) ([]GetStudiosByPerformerAndNetworkRow, error) GetTagAliases(ctx context.Context, tagID uuid.UUID) ([]string, error) GetTagCategoriesByIds(ctx context.Context, dollar_1 []uuid.UUID) ([]TagCategory, error) GetUserNotificationSubscriptions(ctx context.Context, userID uuid.UUID) ([]NotificationType, error) GetUserRoles(ctx context.Context, userID uuid.UUID) ([]string, error) InviteKeyUsed(ctx context.Context, id uuid.UUID) (*int, error) IsImageUnused(ctx context.Context, id uuid.UUID) (bool, error) MarkAllNotificationsRead(ctx context.Context, userID uuid.UUID) error MarkNotificationRead(ctx context.Context, arg MarkNotificationReadParams) error MoveSceneFingerprintSubmissions(ctx context.Context, arg MoveSceneFingerprintSubmissionsParams) (int64, error) QueryModAudits(ctx context.Context, arg QueryModAuditsParams) ([]ModAudit, error) ReassignPerformerAliases(ctx context.Context, arg ReassignPerformerAliasesParams) error ReassignPerformerFavorites(ctx context.Context, arg ReassignPerformerFavoritesParams) error ReassignStudioFavorites(ctx context.Context, arg ReassignStudioFavoritesParams) error ResetVotes(ctx context.Context, editID uuid.UUID) error SearchPerformersWithFacets(ctx context.Context, arg SearchPerformersWithFacetsParams) ([]SearchPerformersWithFacetsRow, error) SearchScenes(ctx context.Context, arg SearchScenesParams) ([]SearchScenesRow, error) SearchStudios(ctx context.Context, arg SearchStudiosParams) ([]SearchStudiosRow, error) SearchTags(ctx context.Context, arg SearchTagsParams) ([]Tag, error) SetScenePerformerAlias(ctx context.Context, arg SetScenePerformerAliasParams) error SoftDeletePerformer(ctx context.Context, id uuid.UUID) (Performer, error) SoftDeleteScene(ctx context.Context, id uuid.UUID) (Scene, error) SoftDeleteStudio(ctx context.Context, id uuid.UUID) (Studio, error) SoftDeleteTag(ctx context.Context, id uuid.UUID) (Tag, error) SubmittedHashExists(ctx context.Context, arg SubmittedHashExistsParams) (bool, error) TriggerDownvoteEditNotifications(ctx context.Context, id uuid.UUID) error TriggerEditCommentNotifications(ctx context.Context, id uuid.UUID) error TriggerFailedEditNotifications(ctx context.Context, id uuid.UUID) error TriggerPerformerEditNotifications(ctx context.Context, id uuid.UUID) error TriggerSceneCreationNotifications(ctx context.Context, id uuid.UUID) error TriggerSceneEditNotifications(ctx context.Context, id uuid.UUID) error TriggerStudioEditNotifications(ctx context.Context, id uuid.UUID) error TriggerUpdatedEditNotifications(ctx context.Context, id uuid.UUID) error UpdateEdit(ctx context.Context, arg UpdateEditParams) (Edit, error) UpdateEditData(ctx context.Context, arg UpdateEditDataParams) (Edit, error) UpdatePerformer(ctx context.Context, arg UpdatePerformerParams) (Performer, error) UpdatePerformerRedirects(ctx context.Context, arg UpdatePerformerRedirectsParams) error UpdateScene(ctx context.Context, arg UpdateSceneParams) (Scene, error) UpdateSceneRedirects(ctx context.Context, arg UpdateSceneRedirectsParams) error UpdateSceneStudios(ctx context.Context, arg UpdateSceneStudiosParams) error UpdateSceneTagsForMerge(ctx context.Context, arg UpdateSceneTagsForMergeParams) error UpdateSite(ctx context.Context, arg UpdateSiteParams) (Site, error) UpdateStudio(ctx context.Context, arg UpdateStudioParams) (Studio, error) UpdateStudioRedirects(ctx context.Context, arg UpdateStudioRedirectsParams) error UpdateTag(ctx context.Context, arg UpdateTagParams) (Tag, error) UpdateTagCategory(ctx context.Context, arg UpdateTagCategoryParams) (TagCategory, error) UpdateTagRedirects(ctx context.Context, arg UpdateTagRedirectsParams) error UpdateUser(ctx context.Context, arg UpdateUserParams) (User, error) UpdateUserAPIKey(ctx context.Context, arg UpdateUserAPIKeyParams) error UpdateUserEmail(ctx context.Context, arg UpdateUserEmailParams) error UpdateUserInviteTokenCount(ctx context.Context, arg UpdateUserInviteTokenCountParams) error UpdateUserPassword(ctx context.Context, arg UpdateUserPasswordParams) error } var _ Querier = (*Queries)(nil) ================================================ FILE: internal/queries/scene.sql.go ================================================ // Code generated by sqlc. DO NOT EDIT. // versions: // sqlc v1.29.0 // source: scene.sql package queries import ( "context" "github.com/gofrs/uuid" ) const countScenesByPerformer = `-- name: CountScenesByPerformer :one SELECT COUNT(*) FROM scene_performers WHERE performer_id = $1 ` func (q *Queries) CountScenesByPerformer(ctx context.Context, performerID uuid.UUID) (int64, error) { row := q.db.QueryRow(ctx, countScenesByPerformer, performerID) var count int64 err := row.Scan(&count) return count, err } const createScene = `-- name: CreateScene :one INSERT INTO scenes (id, title, details, date, production_date, studio_id, duration, director, code, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, now(), now()) RETURNING id, title, details, studio_id, created_at, updated_at, duration, director, deleted, code, date, production_date ` type CreateSceneParams struct { ID uuid.UUID `db:"id" json:"id"` Title *string `db:"title" json:"title"` Details *string `db:"details" json:"details"` Date *string `db:"date" json:"date"` ProductionDate *string `db:"production_date" json:"production_date"` StudioID uuid.NullUUID `db:"studio_id" json:"studio_id"` Duration *int `db:"duration" json:"duration"` Director *string `db:"director" json:"director"` Code *string `db:"code" json:"code"` } // Scene queries func (q *Queries) CreateScene(ctx context.Context, arg CreateSceneParams) (Scene, error) { row := q.db.QueryRow(ctx, createScene, arg.ID, arg.Title, arg.Details, arg.Date, arg.ProductionDate, arg.StudioID, arg.Duration, arg.Director, arg.Code, ) var i Scene err := row.Scan( &i.ID, &i.Title, &i.Details, &i.StudioID, &i.CreatedAt, &i.UpdatedAt, &i.Duration, &i.Director, &i.Deleted, &i.Code, &i.Date, &i.ProductionDate, ) return i, err } type CreateSceneImagesParams struct { SceneID uuid.UUID `db:"scene_id" json:"scene_id"` ImageID uuid.UUID `db:"image_id" json:"image_id"` } type CreateScenePerformersParams struct { SceneID uuid.UUID `db:"scene_id" json:"scene_id"` PerformerID uuid.UUID `db:"performer_id" json:"performer_id"` As *string `db:"as" json:"as"` } const createSceneRedirect = `-- name: CreateSceneRedirect :exec INSERT INTO scene_redirects (source_id, target_id) VALUES ($1, $2) ` type CreateSceneRedirectParams struct { SourceID uuid.UUID `db:"source_id" json:"source_id"` TargetID uuid.UUID `db:"target_id" json:"target_id"` } // Scene redirects func (q *Queries) CreateSceneRedirect(ctx context.Context, arg CreateSceneRedirectParams) error { _, err := q.db.Exec(ctx, createSceneRedirect, arg.SourceID, arg.TargetID) return err } type CreateSceneURLsParams struct { SceneID uuid.UUID `db:"scene_id" json:"scene_id"` Url string `db:"url" json:"url"` SiteID uuid.UUID `db:"site_id" json:"site_id"` } const deleteScene = `-- name: DeleteScene :exec DELETE FROM scenes WHERE id = $1 ` func (q *Queries) DeleteScene(ctx context.Context, id uuid.UUID) error { _, err := q.db.Exec(ctx, deleteScene, id) return err } const deleteSceneImages = `-- name: DeleteSceneImages :exec DELETE FROM scene_images WHERE scene_id = $1 ` // Scene images func (q *Queries) DeleteSceneImages(ctx context.Context, sceneID uuid.UUID) error { _, err := q.db.Exec(ctx, deleteSceneImages, sceneID) return err } const deleteScenePerformers = `-- name: DeleteScenePerformers :exec DELETE FROM scene_performers WHERE scene_id = $1 ` func (q *Queries) DeleteScenePerformers(ctx context.Context, sceneID uuid.UUID) error { _, err := q.db.Exec(ctx, deleteScenePerformers, sceneID) return err } const deleteSceneStudios = `-- name: DeleteSceneStudios :exec UPDATE scenes SET studio_id = NULL WHERE studio_id = $1 ` func (q *Queries) DeleteSceneStudios(ctx context.Context, studioID uuid.NullUUID) error { _, err := q.db.Exec(ctx, deleteSceneStudios, studioID) return err } const deleteSceneURLs = `-- name: DeleteSceneURLs :exec DELETE FROM scene_urls WHERE scene_id = $1 ` func (q *Queries) DeleteSceneURLs(ctx context.Context, sceneID uuid.UUID) error { _, err := q.db.Exec(ctx, deleteSceneURLs, sceneID) return err } const findExistingScenes = `-- name: FindExistingScenes :many SELECT id, title, details, studio_id, created_at, updated_at, duration, director, deleted, code, date, production_date FROM scenes WHERE ( ($1::text IS NOT NULL AND $2::uuid IS NOT NULL AND TRIM(LOWER(title)) = TRIM(LOWER($1)) AND studio_id = $2) OR ($3::BIGINT[] IS NOT NULL AND array_length($3::BIGINT[], 1) > 0 AND id IN ( SELECT scene_id FROM scene_fingerprints SFP JOIN fingerprints FP ON SFP.fingerprint_id = FP.id WHERE FP.hash = ANY($3::BIGINT[]) GROUP BY scene_id )) ) AND deleted = FALSE ` type FindExistingScenesParams struct { Title *string `db:"title" json:"title"` StudioID uuid.NullUUID `db:"studio_id" json:"studio_id"` Hashes []int64 `db:"hashes" json:"hashes"` } func (q *Queries) FindExistingScenes(ctx context.Context, arg FindExistingScenesParams) ([]Scene, error) { rows, err := q.db.Query(ctx, findExistingScenes, arg.Title, arg.StudioID, arg.Hashes) if err != nil { return nil, err } defer rows.Close() items := []Scene{} for rows.Next() { var i Scene if err := rows.Scan( &i.ID, &i.Title, &i.Details, &i.StudioID, &i.CreatedAt, &i.UpdatedAt, &i.Duration, &i.Director, &i.Deleted, &i.Code, &i.Date, &i.ProductionDate, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const findScene = `-- name: FindScene :one SELECT id, title, details, studio_id, created_at, updated_at, duration, director, deleted, code, date, production_date FROM scenes WHERE id = $1 ` func (q *Queries) FindScene(ctx context.Context, id uuid.UUID) (Scene, error) { row := q.db.QueryRow(ctx, findScene, id) var i Scene err := row.Scan( &i.ID, &i.Title, &i.Details, &i.StudioID, &i.CreatedAt, &i.UpdatedAt, &i.Duration, &i.Director, &i.Deleted, &i.Code, &i.Date, &i.ProductionDate, ) return i, err } const findSceneAppearancesByIds = `-- name: FindSceneAppearancesByIds :many SELECT scene_id, performer_id, "as" FROM scene_performers WHERE scene_id = ANY($1::UUID[]) ` type FindSceneAppearancesByIdsRow struct { SceneID uuid.UUID `db:"scene_id" json:"scene_id"` PerformerID uuid.UUID `db:"performer_id" json:"performer_id"` As *string `db:"as" json:"as"` } // Get performer appearances for multiple scenes func (q *Queries) FindSceneAppearancesByIds(ctx context.Context, sceneIds []uuid.UUID) ([]FindSceneAppearancesByIdsRow, error) { rows, err := q.db.Query(ctx, findSceneAppearancesByIds, sceneIds) if err != nil { return nil, err } defer rows.Close() items := []FindSceneAppearancesByIdsRow{} for rows.Next() { var i FindSceneAppearancesByIdsRow if err := rows.Scan(&i.SceneID, &i.PerformerID, &i.As); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const findSceneByURL = `-- name: FindSceneByURL :many SELECT s.id, s.title, s.details, s.studio_id, s.created_at, s.updated_at, s.duration, s.director, s.deleted, s.code, s.date, s.production_date FROM scenes S JOIN scene_urls SU ON SU.scene_id = S.id WHERE LOWER(SU.url) = LOWER($1) AND S.deleted = FALSE LIMIT $2 ` type FindSceneByURLParams struct { Url *string `db:"url" json:"url"` Limit int32 `db:"limit" json:"limit"` } func (q *Queries) FindSceneByURL(ctx context.Context, arg FindSceneByURLParams) ([]Scene, error) { rows, err := q.db.Query(ctx, findSceneByURL, arg.Url, arg.Limit) if err != nil { return nil, err } defer rows.Close() items := []Scene{} for rows.Next() { var i Scene if err := rows.Scan( &i.ID, &i.Title, &i.Details, &i.StudioID, &i.CreatedAt, &i.UpdatedAt, &i.Duration, &i.Director, &i.Deleted, &i.Code, &i.Date, &i.ProductionDate, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const findSceneUrlsByIds = `-- name: FindSceneUrlsByIds :many SELECT scene_id, url, site_id FROM scene_urls WHERE scene_id = ANY($1::UUID[]) ` // Get URLs for multiple scenes func (q *Queries) FindSceneUrlsByIds(ctx context.Context, sceneIds []uuid.UUID) ([]SceneUrl, error) { rows, err := q.db.Query(ctx, findSceneUrlsByIds, sceneIds) if err != nil { return nil, err } defer rows.Close() items := []SceneUrl{} for rows.Next() { var i SceneUrl if err := rows.Scan(&i.SceneID, &i.Url, &i.SiteID); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const findScenesByFullFingerprintsWithHash = `-- name: FindScenesByFullFingerprintsWithHash :many SELECT scenes.id, scenes.title, scenes.details, scenes.studio_id, scenes.created_at, scenes.updated_at, scenes.duration, scenes.director, scenes.deleted, scenes.code, scenes.date, scenes.production_date, matches.hash FROM ( SELECT SFP.scene_id AS id, FP.hash FROM UNNEST($1::BIGINT[]) phash JOIN fingerprints FP ON FP.hash <@ (phash, $2::INTEGER) AND FP.algorithm = 'PHASH' JOIN scene_fingerprints SFP ON SFP.fingerprint_id = FP.id WHERE $1::BIGINT[] IS NOT NULL AND array_length($1::BIGINT[], 1) > 0 GROUP BY SFP.scene_id, FP.hash UNION SELECT SFP.scene_id AS id, FP.hash FROM scene_fingerprints SFP JOIN fingerprints FP ON SFP.fingerprint_id = FP.id WHERE FP.hash = ANY($3::BIGINT[]) AND $3::BIGINT[] IS NOT NULL AND array_length($3::BIGINT[], 1) > 0 GROUP BY SFP.scene_id, FP.hash ) matches JOIN scenes ON scenes.id = matches.id AND scenes.deleted = FALSE ` type FindScenesByFullFingerprintsWithHashParams struct { Phashes []int64 `db:"phashes" json:"phashes"` Distance int `db:"distance" json:"distance"` Hashes []int64 `db:"hashes" json:"hashes"` } type FindScenesByFullFingerprintsWithHashRow struct { Scene Scene `db:"scene" json:"scene"` Hash int64 `db:"hash" json:"hash"` } // Scene fingerprints (use fingerprint.sql for most fingerprint operations) func (q *Queries) FindScenesByFullFingerprintsWithHash(ctx context.Context, arg FindScenesByFullFingerprintsWithHashParams) ([]FindScenesByFullFingerprintsWithHashRow, error) { rows, err := q.db.Query(ctx, findScenesByFullFingerprintsWithHash, arg.Phashes, arg.Distance, arg.Hashes) if err != nil { return nil, err } defer rows.Close() items := []FindScenesByFullFingerprintsWithHashRow{} for rows.Next() { var i FindScenesByFullFingerprintsWithHashRow if err := rows.Scan( &i.Scene.ID, &i.Scene.Title, &i.Scene.Details, &i.Scene.StudioID, &i.Scene.CreatedAt, &i.Scene.UpdatedAt, &i.Scene.Duration, &i.Scene.Director, &i.Scene.Deleted, &i.Scene.Code, &i.Scene.Date, &i.Scene.ProductionDate, &i.Hash, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getScenePerformers = `-- name: GetScenePerformers :many SELECT p.id, p.name, p.disambiguation, p.gender, p.ethnicity, p.country, p.eye_color, p.hair_color, p.height, p.cup_size, p.band_size, p.hip_size, p.waist_size, p.breast_type, p.career_start_year, p.career_end_year, p.created_at, p.updated_at, p.deleted, p.birthdate, p.deathdate, "as" FROM scene_performers SP JOIN performers P ON SP.performer_id = P.id WHERE scene_id = $1 ` type GetScenePerformersRow struct { Performer Performer `db:"performer" json:"performer"` As *string `db:"as" json:"as"` } func (q *Queries) GetScenePerformers(ctx context.Context, sceneID uuid.UUID) ([]GetScenePerformersRow, error) { rows, err := q.db.Query(ctx, getScenePerformers, sceneID) if err != nil { return nil, err } defer rows.Close() items := []GetScenePerformersRow{} for rows.Next() { var i GetScenePerformersRow if err := rows.Scan( &i.Performer.ID, &i.Performer.Name, &i.Performer.Disambiguation, &i.Performer.Gender, &i.Performer.Ethnicity, &i.Performer.Country, &i.Performer.EyeColor, &i.Performer.HairColor, &i.Performer.Height, &i.Performer.CupSize, &i.Performer.BandSize, &i.Performer.HipSize, &i.Performer.WaistSize, &i.Performer.BreastType, &i.Performer.CareerStartYear, &i.Performer.CareerEndYear, &i.Performer.CreatedAt, &i.Performer.UpdatedAt, &i.Performer.Deleted, &i.Performer.Birthdate, &i.Performer.Deathdate, &i.As, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getSceneURLs = `-- name: GetSceneURLs :many SELECT url, site_id FROM scene_urls WHERE scene_id = $1 ` type GetSceneURLsRow struct { Url string `db:"url" json:"url"` SiteID uuid.UUID `db:"site_id" json:"site_id"` } func (q *Queries) GetSceneURLs(ctx context.Context, sceneID uuid.UUID) ([]GetSceneURLsRow, error) { rows, err := q.db.Query(ctx, getSceneURLs, sceneID) if err != nil { return nil, err } defer rows.Close() items := []GetSceneURLsRow{} for rows.Next() { var i GetSceneURLsRow if err := rows.Scan(&i.Url, &i.SiteID); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getScenes = `-- name: GetScenes :many SELECT id, title, details, studio_id, created_at, updated_at, duration, director, deleted, code, date, production_date FROM scenes WHERE id = ANY($1::UUID[]) ORDER BY title ` func (q *Queries) GetScenes(ctx context.Context, dollar_1 []uuid.UUID) ([]Scene, error) { rows, err := q.db.Query(ctx, getScenes, dollar_1) if err != nil { return nil, err } defer rows.Close() items := []Scene{} for rows.Next() { var i Scene if err := rows.Scan( &i.ID, &i.Title, &i.Details, &i.StudioID, &i.CreatedAt, &i.UpdatedAt, &i.Duration, &i.Director, &i.Deleted, &i.Code, &i.Date, &i.ProductionDate, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const searchScenes = `-- name: SearchScenes :many SELECT scene_id, pdb.agg('{"value_count": {"field": "scene_id"}}') OVER () as total_count FROM scene_search WHERE scene_id @@@ paradedb.disjunction_max(disjuncts => ARRAY[ paradedb.match(field => 'scene_title', value => $1::TEXT), paradedb.match(field => 'scene_code', value => $1::TEXT), paradedb.boolean( should => ARRAY[ paradedb.match(field => 'performer_names', value => $1::TEXT), paradedb.match(field => 'studio_name', value => $1::TEXT), paradedb.match(field => 'network_name', value => $1::TEXT) ] ) ]) ORDER BY pdb.score(scene_id) DESC LIMIT $3 OFFSET $2 ` type SearchScenesParams struct { Term *string `db:"term" json:"term"` Offset int32 `db:"offset" json:"offset"` Limit int32 `db:"limit" json:"limit"` } type SearchScenesRow struct { SceneID uuid.UUID `db:"scene_id" json:"scene_id"` TotalCount interface{} `db:"total_count" json:"total_count"` } func (q *Queries) SearchScenes(ctx context.Context, arg SearchScenesParams) ([]SearchScenesRow, error) { rows, err := q.db.Query(ctx, searchScenes, arg.Term, arg.Offset, arg.Limit) if err != nil { return nil, err } defer rows.Close() items := []SearchScenesRow{} for rows.Next() { var i SearchScenesRow if err := rows.Scan(&i.SceneID, &i.TotalCount); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const softDeleteScene = `-- name: SoftDeleteScene :one UPDATE scenes SET deleted = true, updated_at = NOW() WHERE id = $1 RETURNING id, title, details, studio_id, created_at, updated_at, duration, director, deleted, code, date, production_date ` func (q *Queries) SoftDeleteScene(ctx context.Context, id uuid.UUID) (Scene, error) { row := q.db.QueryRow(ctx, softDeleteScene, id) var i Scene err := row.Scan( &i.ID, &i.Title, &i.Details, &i.StudioID, &i.CreatedAt, &i.UpdatedAt, &i.Duration, &i.Director, &i.Deleted, &i.Code, &i.Date, &i.ProductionDate, ) return i, err } const updateScene = `-- name: UpdateScene :one UPDATE scenes SET title = $2, details = $3, date = $4, production_date = $5, studio_id = $6, duration = $7, director = $8, code = $9, updated_at = now() WHERE id = $1 RETURNING id, title, details, studio_id, created_at, updated_at, duration, director, deleted, code, date, production_date ` type UpdateSceneParams struct { ID uuid.UUID `db:"id" json:"id"` Title *string `db:"title" json:"title"` Details *string `db:"details" json:"details"` Date *string `db:"date" json:"date"` ProductionDate *string `db:"production_date" json:"production_date"` StudioID uuid.NullUUID `db:"studio_id" json:"studio_id"` Duration *int `db:"duration" json:"duration"` Director *string `db:"director" json:"director"` Code *string `db:"code" json:"code"` } func (q *Queries) UpdateScene(ctx context.Context, arg UpdateSceneParams) (Scene, error) { row := q.db.QueryRow(ctx, updateScene, arg.ID, arg.Title, arg.Details, arg.Date, arg.ProductionDate, arg.StudioID, arg.Duration, arg.Director, arg.Code, ) var i Scene err := row.Scan( &i.ID, &i.Title, &i.Details, &i.StudioID, &i.CreatedAt, &i.UpdatedAt, &i.Duration, &i.Director, &i.Deleted, &i.Code, &i.Date, &i.ProductionDate, ) return i, err } const updateSceneRedirects = `-- name: UpdateSceneRedirects :exec UPDATE scene_redirects SET target_id = $1 WHERE target_id = $2 ` type UpdateSceneRedirectsParams struct { NewTargetID uuid.UUID `db:"new_target_id" json:"new_target_id"` OldTargetID uuid.UUID `db:"old_target_id" json:"old_target_id"` } func (q *Queries) UpdateSceneRedirects(ctx context.Context, arg UpdateSceneRedirectsParams) error { _, err := q.db.Exec(ctx, updateSceneRedirects, arg.NewTargetID, arg.OldTargetID) return err } const updateSceneStudios = `-- name: UpdateSceneStudios :exec UPDATE scenes SET studio_id = $1 WHERE studio_id = $2 ` type UpdateSceneStudiosParams struct { TargetID uuid.NullUUID `db:"target_id" json:"target_id"` SourceID uuid.NullUUID `db:"source_id" json:"source_id"` } func (q *Queries) UpdateSceneStudios(ctx context.Context, arg UpdateSceneStudiosParams) error { _, err := q.db.Exec(ctx, updateSceneStudios, arg.TargetID, arg.SourceID) return err } ================================================ FILE: internal/queries/site.sql.go ================================================ // Code generated by sqlc. DO NOT EDIT. // versions: // sqlc v1.29.0 // source: site.sql package queries import ( "context" "github.com/gofrs/uuid" ) const createSite = `-- name: CreateSite :one INSERT INTO sites (id, name, description, url, regex, valid_types, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, now(), now()) RETURNING id, name, description, url, regex, valid_types, created_at, updated_at ` type CreateSiteParams struct { ID uuid.UUID `db:"id" json:"id"` Name string `db:"name" json:"name"` Description *string `db:"description" json:"description"` Url *string `db:"url" json:"url"` Regex *string `db:"regex" json:"regex"` ValidTypes []string `db:"valid_types" json:"valid_types"` } // Site queries func (q *Queries) CreateSite(ctx context.Context, arg CreateSiteParams) (Site, error) { row := q.db.QueryRow(ctx, createSite, arg.ID, arg.Name, arg.Description, arg.Url, arg.Regex, arg.ValidTypes, ) var i Site err := row.Scan( &i.ID, &i.Name, &i.Description, &i.Url, &i.Regex, &i.ValidTypes, &i.CreatedAt, &i.UpdatedAt, ) return i, err } const deleteSite = `-- name: DeleteSite :exec DELETE FROM sites WHERE id = $1 ` func (q *Queries) DeleteSite(ctx context.Context, id uuid.UUID) error { _, err := q.db.Exec(ctx, deleteSite, id) return err } const findSitesByIds = `-- name: FindSitesByIds :many SELECT id, name, description, url, regex, valid_types, created_at, updated_at FROM sites WHERE id = ANY($1::UUID[]) ` func (q *Queries) FindSitesByIds(ctx context.Context, dollar_1 []uuid.UUID) ([]Site, error) { rows, err := q.db.Query(ctx, findSitesByIds, dollar_1) if err != nil { return nil, err } defer rows.Close() items := []Site{} for rows.Next() { var i Site if err := rows.Scan( &i.ID, &i.Name, &i.Description, &i.Url, &i.Regex, &i.ValidTypes, &i.CreatedAt, &i.UpdatedAt, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getSite = `-- name: GetSite :one SELECT id, name, description, url, regex, valid_types, created_at, updated_at FROM sites WHERE id = $1 ` func (q *Queries) GetSite(ctx context.Context, id uuid.UUID) (Site, error) { row := q.db.QueryRow(ctx, getSite, id) var i Site err := row.Scan( &i.ID, &i.Name, &i.Description, &i.Url, &i.Regex, &i.ValidTypes, &i.CreatedAt, &i.UpdatedAt, ) return i, err } const updateSite = `-- name: UpdateSite :one UPDATE sites SET name = $2, description = $3, url = $4, regex = $5, valid_types = $6, updated_at = now() WHERE id = $1 RETURNING id, name, description, url, regex, valid_types, created_at, updated_at ` type UpdateSiteParams struct { ID uuid.UUID `db:"id" json:"id"` Name string `db:"name" json:"name"` Description *string `db:"description" json:"description"` Url *string `db:"url" json:"url"` Regex *string `db:"regex" json:"regex"` ValidTypes []string `db:"valid_types" json:"valid_types"` } func (q *Queries) UpdateSite(ctx context.Context, arg UpdateSiteParams) (Site, error) { row := q.db.QueryRow(ctx, updateSite, arg.ID, arg.Name, arg.Description, arg.Url, arg.Regex, arg.ValidTypes, ) var i Site err := row.Scan( &i.ID, &i.Name, &i.Description, &i.Url, &i.Regex, &i.ValidTypes, &i.CreatedAt, &i.UpdatedAt, ) return i, err } ================================================ FILE: internal/queries/sql/draft.sql ================================================ -- Draft queries -- name: CreateDraft :one INSERT INTO drafts (id, user_id, type, data, created_at) VALUES ($1, $2, $3, $4, now()) RETURNING *; -- name: DeleteDraft :exec DELETE FROM drafts WHERE id = $1; -- name: FindDraft :one SELECT * FROM drafts WHERE id = $1; -- name: FindDraftsByUser :many SELECT * FROM drafts WHERE user_id = $1; -- name: DeleteExpiredDrafts :exec DELETE FROM drafts WHERE created_at <= (now()::timestamp - (INTERVAL '1 second' * $1)); ================================================ FILE: internal/queries/sql/edit.sql ================================================ -- Edit queries -- name: CreateEdit :one INSERT INTO edits ( id, user_id, target_type, operation, data, votes, status, applied, bot, created_at ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, now()) RETURNING *; -- name: UpdateEdit :one UPDATE edits SET data = $2, votes = $3, status = $4, applied = $5, closed_at = $6, update_count = $7, updated_at = now() WHERE id = $1 RETURNING *; -- name: DeleteEdit :exec DELETE FROM edits WHERE id = $1; -- name: FindEdit :one SELECT * FROM edits WHERE id = $1; -- name: CancelUserEdits :exec UPDATE edits SET status = 'CANCELED', updated_at = NOW() WHERE user_id = $1; -- name: FindPendingPerformerCreation :many SELECT * FROM edits WHERE status = 'PENDING' AND target_type = 'PERFORMER' AND ( (sqlc.narg('name')::text IS NOT NULL AND data->'new_data'->>'name' = sqlc.narg('name')) OR (sqlc.narg('urls')::text[] IS NOT NULL AND jsonb_exists_any(jsonb_path_query_array(data, '$.new_data.added_urls[*].url'), sqlc.narg('urls'))) ); -- name: FindPendingSceneCreation :many SELECT * FROM edits WHERE status = 'PENDING' AND target_type = 'SCENE' AND ( (sqlc.narg('title')::text IS NOT NULL AND sqlc.narg('studio_id')::uuid IS NOT NULL AND data->'new_data'->>'title' = sqlc.narg('title') AND (data->'new_data'->>'studio_id')::uuid = sqlc.narg('studio_id')) OR (sqlc.narg('hashes')::text[] IS NOT NULL AND jsonb_exists_any(jsonb_path_query_array(data, '$.new_data.added_fingerprints[*].hash'), sqlc.narg('hashes'))) ); -- name: GetEditsByPerformer :many SELECT e.* FROM edits e JOIN performer_edits pe ON e.id = pe.edit_id WHERE pe.performer_id = $1 ORDER BY e.created_at DESC; -- name: GetEditsByStudio :many SELECT e.* FROM edits e JOIN studio_edits se ON e.id = se.edit_id WHERE se.studio_id = $1 ORDER BY e.created_at DESC; -- name: CreateTagEdit :exec INSERT INTO tag_edits (edit_id, tag_id) VALUES ($1, $2); -- name: CreateStudioEdit :exec INSERT INTO studio_edits (edit_id, studio_id) VALUES ($1, $2); -- name: CreateSceneEdit :exec INSERT INTO scene_edits (edit_id, scene_id) VALUES ($1, $2); -- name: CreatePerformerEdit :exec INSERT INTO performer_edits (edit_id, performer_id) VALUES ($1, $2); -- name: GetEditsByTag :many SELECT e.* FROM edits e JOIN tag_edits te ON e.id = te.edit_id WHERE te.tag_id = $1 ORDER BY e.created_at DESC; -- name: GetEditsByScene :many SELECT e.* FROM edits e JOIN scene_edits se ON e.id = se.edit_id WHERE se.scene_id = $1 ORDER BY e.created_at DESC; -- Edit comments -- name: CreateEditComment :one INSERT INTO edit_comments (id, edit_id, user_id, text, created_at) VALUES ($1, $2, $3, $4, NOW()) RETURNING *; -- name: GetEditComments :many SELECT * FROM edit_comments WHERE edit_id = $1 ORDER BY created_at ASC; -- Edit votes -- name: CreateEditVote :exec INSERT INTO edit_votes (edit_id, user_id, vote, created_at) VALUES ($1, $2, $3, NOW()) ON CONFLICT(edit_id, user_id) DO UPDATE SET (vote, created_at) = ($3, NOW()); -- name: GetEditVotes :many SELECT * FROM edit_votes WHERE edit_id = $1; -- name: ResetVotes :exec UPDATE edit_votes SET vote = 'ABSTAIN' WHERE edit_id = $1; -- URL merging queries for edits -- name: GetMergedURLsForEdit :many -- result: URL -- Gets current URLs for target entity and merges with edit's added_urls/removed_urls WITH current_urls AS ( SELECT su.url, su.site_id FROM edits e JOIN scene_edits se ON e.id = se.edit_id JOIN scene_urls su ON se.scene_id = su.scene_id WHERE e.id = $1 AND e.target_type = 'SCENE' UNION ALL SELECT pu.url, pu.site_id FROM edits e JOIN performer_edits pe ON e.id = pe.edit_id JOIN performer_urls pu ON pe.performer_id = pu.performer_id WHERE e.id = $1 AND e.target_type = 'PERFORMER' UNION ALL SELECT stu.url, stu.site_id FROM edits e JOIN studio_edits ste ON e.id = ste.edit_id JOIN studio_urls stu ON ste.studio_id = stu.studio_id WHERE e.id = $1 AND e.target_type = 'STUDIO' ), removed_urls AS ( SELECT elem->>'url' AS url, (elem->>'site_id')::uuid AS site_id FROM edits, jsonb_array_elements(COALESCE(data->'new_data'->'removed_urls', '[]'::jsonb)) AS elem WHERE id = $1 ), added_urls AS ( SELECT elem->>'url' AS url, (elem->>'site_id')::uuid AS site_id FROM edits, jsonb_array_elements(COALESCE(data->'new_data'->'added_urls', '[]'::jsonb)) AS elem WHERE id = $1 ), final_urls AS ( SELECT url, site_id FROM current_urls WHERE (url, site_id) NOT IN (SELECT url, site_id FROM removed_urls) UNION SELECT url, site_id FROM added_urls ) SELECT DISTINCT url, site_id FROM final_urls ORDER BY url; -- name: GetImagesForEdit :many -- Gets current images for target entity and merges with edit's added_images/removed_images WITH edit AS ( SELECT * FROM edits WHERE edits.id = $1 ), current_images AS ( SELECT si.image_id FROM edit e JOIN scene_edits se ON e.id = se.edit_id JOIN scene_images si ON se.scene_id = si.scene_id UNION ALL SELECT pi.image_id FROM edit e JOIN performer_edits pe ON e.id = pe.edit_id JOIN performer_images pi ON pe.performer_id = pi.performer_id UNION ALL SELECT sti.image_id FROM edit e JOIN studio_edits ste ON e.id = ste.edit_id JOIN studio_images sti ON ste.studio_id = sti.studio_id ), removed_images AS ( SELECT jsonb_array_elements_text(COALESCE(data->'new_data'->'removed_images', '[]'::jsonb))::uuid AS image_id FROM edit ), added_images AS ( SELECT jsonb_array_elements_text(COALESCE(data->'new_data'->'added_images', '[]'::jsonb))::uuid AS image_id FROM edit ), final_images AS ( SELECT image_id FROM current_images WHERE image_id NOT IN (SELECT image_id FROM removed_images) UNION SELECT image_id FROM added_images ) SELECT i.* FROM final_images fi JOIN images i ON fi.image_id = i.id ORDER BY i.id; -- name: GetEditTargetID :one SELECT CASE e.target_type WHEN 'SCENE' THEN se.scene_id WHEN 'PERFORMER' THEN pe.performer_id WHEN 'STUDIO' THEN ste.studio_id WHEN 'TAG' THEN te.tag_id END::UUID AS id, e.target_type FROM edits e LEFT JOIN scene_edits se ON e.id = se.edit_id LEFT JOIN performer_edits pe ON e.id = pe.edit_id LEFT JOIN studio_edits ste ON e.id = ste.edit_id LEFT JOIN tag_edits te ON e.id = te.edit_id WHERE e.id = $1; -- name: GetEditPerformerAliases :many WITH edit AS ( SELECT * FROM edits WHERE id = $1 ) ( SELECT alias FROM edit E JOIN performer_edits PE ON E.id = PE.edit_id JOIN performer_aliases PA ON PE.performer_id = PA.performer_id EXCEPT SELECT jsonb_array_elements_text(COALESCE(data->'new_data'->'removed_aliases', '[]'::jsonb)) AS alias FROM edit ) UNION SELECT jsonb_array_elements_text(COALESCE(data->'new_data'->'added_aliases', '[]'::jsonb)) AS alias FROM edit; -- name: GetEditPerformerTattoos :many WITH edit AS ( SELECT * FROM edits WHERE id = $1 ), current_tattoos AS ( SELECT location, description FROM edit E JOIN performer_edits PE ON E.id = PE.edit_id JOIN performer_tattoos PT ON PE.performer_id = PT.performer_id ), removed_tattoos AS ( SELECT elem->>'location' AS location, elem->>'description' AS description FROM edit, jsonb_array_elements(COALESCE(data->'new_data'->'removed_tattoos', '[]'::jsonb)) AS elem ), added_tattoos AS ( SELECT elem->>'location' AS location, elem->>'description' AS description FROM edit, jsonb_array_elements(COALESCE(data->'new_data'->'added_tattoos', '[]'::jsonb)) AS elem ), final_tattoos AS ( SELECT * FROM current_tattoos EXCEPT SELECT * FROM removed_tattoos UNION SELECT * FROM added_tattoos ) SELECT DISTINCT location, description FROM final_tattoos; -- name: GetEditPerformerPiercings :many WITH edit AS ( SELECT * FROM edits WHERE id = $1 ), current_piercings AS ( SELECT location, description FROM edit E JOIN performer_edits PE ON E.id = PE.edit_id JOIN performer_piercings PP ON PE.performer_id = PP.performer_id ), removed_piercings AS ( SELECT elem->>'location' AS location, elem->>'description' AS description FROM edit, jsonb_array_elements(COALESCE(data->'new_data'->'removed_piercings', '[]'::jsonb)) AS elem ), added_piercings AS ( SELECT elem->>'location' AS location, elem->>'description' AS description FROM edit, jsonb_array_elements(COALESCE(data->'new_data'->'added_piercings', '[]'::jsonb)) AS elem ), final_piercings AS ( SELECT * FROM current_piercings EXCEPT SELECT * FROM removed_piercings UNION SELECT * FROM added_piercings ) SELECT DISTINCT location, description FROM final_piercings; -- name: GetMergedTagsForEdit :many -- Gets current tags for target entity and merges with edit's added_tags/removed_tags WITH edit AS ( SELECT * FROM edits WHERE edits.id = $1 ), current_tags AS ( SELECT st.tag_id FROM edit e JOIN scene_edits se ON e.id = se.edit_id JOIN scene_tags st ON se.scene_id = st.scene_id WHERE e.target_type = 'SCENE' ), removed_tags AS ( SELECT jsonb_array_elements_text(COALESCE(data->'new_data'->'removed_tags', '[]'::jsonb))::uuid AS tag_id FROM edit ), added_tags AS ( SELECT jsonb_array_elements_text(COALESCE(data->'new_data'->'added_tags', '[]'::jsonb))::uuid AS tag_id FROM edit ), final_tags AS ( SELECT tag_id FROM current_tags EXCEPT SELECT tag_id FROM removed_tags UNION SELECT tag_id FROM added_tags ) SELECT t.* FROM final_tags ft JOIN tags t ON ft.tag_id = t.id WHERE t.deleted = FALSE ORDER BY t.name; -- name: GetMergedPerformersForEdit :many -- Gets current performers for target entity and merges with edit's added_performers/removed_performers WITH edit AS ( SELECT * FROM edits WHERE edits.id = $1 ), current_performers AS ( SELECT sp.performer_id, sp."as" FROM edit e JOIN scene_edits se ON e.id = se.edit_id JOIN scene_performers sp ON se.scene_id = sp.scene_id WHERE e.target_type = 'SCENE' ), removed_performers AS ( SELECT (elem->>'performer_id')::uuid AS performer_id, elem->>'as' AS "as" FROM edit, jsonb_array_elements(COALESCE(data->'new_data'->'removed_performers', '[]'::jsonb)) AS elem ), added_performers AS ( SELECT (elem->>'performer_id')::uuid AS performer_id, elem->>'as' AS "as" FROM edit, jsonb_array_elements(COALESCE(data->'new_data'->'added_performers', '[]'::jsonb)) AS elem ), final_performers AS ( SELECT performer_id, "as" FROM current_performers EXCEPT SELECT performer_id, "as" FROM removed_performers UNION SELECT performer_id, "as" FROM added_performers ) SELECT sqlc.embed(p), fp."as" FROM final_performers fp JOIN performers p ON fp.performer_id = p.id WHERE p.deleted = FALSE ORDER BY p.name; -- name: GetMergedStudioAliasesForEdit :many -- Gets current aliases for target studio entity and merges with edit's added_aliases/removed_aliases WITH edit AS ( SELECT * FROM edits WHERE id = $1 ) ( SELECT alias FROM edit E JOIN studio_edits SE ON E.id = SE.edit_id JOIN studio_aliases SA ON SE.studio_id = SA.studio_id WHERE E.target_type = 'STUDIO' EXCEPT SELECT jsonb_array_elements_text(COALESCE(data->'new_data'->'removed_aliases', '[]'::jsonb)) AS alias FROM edit ) UNION SELECT jsonb_array_elements_text(COALESCE(data->'new_data'->'added_aliases', '[]'::jsonb)) AS alias FROM edit; -- name: GetMergedTagAliasesForEdit :many -- Gets current aliases for target tag entity and merges with edit's added_aliases/removed_aliases WITH edit AS ( SELECT * FROM edits WHERE id = $1 ) ( SELECT alias FROM edit E JOIN tag_edits TE ON E.id = TE.edit_id JOIN tag_aliases TA ON TE.tag_id = TA.tag_id EXCEPT SELECT jsonb_array_elements_text(COALESCE(data->'new_data'->'removed_aliases', '[]'::jsonb)) AS alias FROM edit ) UNION SELECT jsonb_array_elements_text(COALESCE(data->'new_data'->'added_aliases', '[]'::jsonb)) AS alias FROM edit; -- name: FindCompletedEdits :many -- Returns pending edits that fulfill one of the criteria for being closed: -- * The full voting period has passed -- * The minimum voting period has passed, and the number of votes has crossed the voting threshold. -- The latter only applies for destructive edits. Non-destructive edits get auto-applied when sufficient votes are cast. SELECT * FROM edits WHERE status = 'PENDING' AND ( (created_at <= (now()::timestamp - (INTERVAL '1 second' * sqlc.arg('voting_period'))) AND updated_at IS NULL) OR (updated_at <= (now()::timestamp - (INTERVAL '1 second' * sqlc.arg('voting_period'))) AND updated_at IS NOT NULL) OR ( votes >= sqlc.arg('minimum_votes') AND ( (created_at <= (now()::timestamp - (INTERVAL '1 second' * sqlc.arg('minimum_voting_period'))) AND updated_at IS NULL) OR (updated_at <= (now()::timestamp - (INTERVAL '1 second' * sqlc.arg('minimum_voting_period'))) AND updated_at IS NOT NULL) ) ) ); -- name: GetEditsByIds :many SELECT * FROM edits WHERE id = ANY($1::UUID[]); -- name: GetEditCommentsByIds :many SELECT * FROM edit_comments WHERE id = ANY($1::UUID[]); -- name: UpdateEditData :one UPDATE edits SET data = $2, updated_at = now() WHERE id = $1 RETURNING *; ================================================ FILE: internal/queries/sql/fingerprint.sql ================================================ -- Fingerprint queries (normalized schema) -- name: CreateFingerprint :one INSERT INTO fingerprints (hash, algorithm) VALUES ($1, $2) ON CONFLICT (hash, algorithm) DO UPDATE SET hash = EXCLUDED.hash RETURNING *; -- name: GetFingerprint :one SELECT * FROM fingerprints WHERE hash = $1 AND algorithm = $2; -- name: SubmittedHashExists :one SELECT EXISTS( SELECT 1 FROM scene_fingerprints f JOIN fingerprints fp ON f.fingerprint_id = fp.id WHERE f.scene_id = $1 AND fp.hash = $2 AND fp.algorithm = $3 AND f.vote = 1 ) AS exists; -- name: CreateSceneFingerprints :copyfrom INSERT INTO scene_fingerprints (fingerprint_id, scene_id, user_id, duration) VALUES ($1, $2, $3, $4); -- name: CreateOrReplaceFingerprint :exec INSERT INTO scene_fingerprints (fingerprint_id, scene_id, user_id, duration, vote) VALUES ($1, $2, $3, $4, $5) ON CONFLICT ON CONSTRAINT scene_fingerprints_scene_id_fingerprint_id_user_id_key DO UPDATE SET duration = EXCLUDED.duration, vote = EXCLUDED.vote; -- name: DeleteSceneFingerprintsByScene :exec DELETE FROM scene_fingerprints WHERE scene_id = $1; -- name: DeleteSceneFingerprint :exec DELETE FROM scene_fingerprints SFP USING fingerprints FP WHERE SFP.fingerprint_id = FP.id AND FP.hash = $1 AND FP.algorithm = $2 AND user_id = $3 AND scene_id = $4; -- name: GetAllSceneFingerprints :many SELECT f.algorithm, f.hash, sf.duration, sf.created_at, sf.user_id FROM scene_fingerprints sf JOIN fingerprints f ON sf.fingerprint_id = f.id WHERE sf.scene_id = $1 ORDER BY f.algorithm, sf.created_at; -- name: GetAllFingerprints :many -- Get all fingerprints for multiple scenes with aggregated vote data -- When onlySubmitted is true, pass the actual user ID, when false pass NULL SELECT SFP.scene_id, FP.hash, FP.algorithm, mode() WITHIN GROUP (ORDER BY SFP.duration)::INTEGER as duration, COUNT(CASE WHEN SFP.vote = 1 THEN 1 END) as submissions, COUNT(CASE WHEN SFP.vote = -1 THEN 1 END) as reports, SUM(SFP.vote) as net_submissions, MIN(SFP.created_at)::TIMESTAMP as created_at, MAX(SFP.created_at)::TIMESTAMP as updated_at, bool_or(SFP.user_id = sqlc.arg(current_user_id) AND SFP.vote = 1) as user_submitted, bool_or(SFP.user_id = sqlc.arg(current_user_id) AND SFP.vote = -1) as user_reported FROM scene_fingerprints SFP JOIN fingerprints FP ON SFP.fingerprint_id = FP.id WHERE SFP.scene_id = ANY(sqlc.arg(scene_ids)::UUID[]) AND (sqlc.narg(filter_user_id)::uuid IS NULL OR SFP.user_id = sqlc.narg(filter_user_id)) GROUP BY SFP.scene_id, FP.algorithm, FP.hash ORDER BY net_submissions DESC; -- name: MoveSceneFingerprintSubmissions :execrows WITH to_move AS ( SELECT SFP.fingerprint_id, SFP.user_id FROM scene_fingerprints SFP JOIN fingerprints FP ON SFP.fingerprint_id = FP.id WHERE FP.hash = sqlc.arg(hash) AND FP.algorithm = sqlc.arg(algorithm) AND SFP.scene_id = sqlc.arg(source_scene_id) ), deleted AS ( DELETE FROM scene_fingerprints WHERE scene_id = sqlc.arg(target_scene_id) AND (fingerprint_id, user_id) IN (SELECT fingerprint_id, user_id FROM to_move) ) UPDATE scene_fingerprints SFP SET scene_id = sqlc.arg(target_scene_id) FROM fingerprints FP WHERE SFP.fingerprint_id = FP.id AND FP.hash = sqlc.arg(hash) AND FP.algorithm = sqlc.arg(algorithm) AND SFP.scene_id = sqlc.arg(source_scene_id); -- name: DeleteAllSceneFingerprintSubmissions :execrows DELETE FROM scene_fingerprints SFP USING fingerprints FP WHERE SFP.fingerprint_id = FP.id AND FP.hash = $1 AND FP.algorithm = $2 AND SFP.scene_id = $3; ================================================ FILE: internal/queries/sql/image.sql ================================================ -- Image queries -- name: CreateImage :one INSERT INTO images (id, url, width, height, checksum) VALUES ($1, $2, $3, $4, $5) RETURNING *; -- name: DeleteImage :exec DELETE FROM images WHERE id = $1; -- name: FindImage :one SELECT * FROM images WHERE id = $1; -- name: FindImageByChecksum :one SELECT * FROM images WHERE checksum = $1; -- name: FindImagesBySceneID :many SELECT images.* FROM images LEFT JOIN scene_images as scenes_join on scenes_join.image_id = images.id LEFT JOIN scenes on scenes_join.scene_id = scenes.id WHERE scenes.id = $1; -- name: FindImagesByStudioID :many SELECT images.* FROM images LEFT JOIN studio_images as studios_join on studios_join.image_id = images.id LEFT JOIN studios on studios_join.studio_id = studios.id WHERE studios.id = $1; -- name: FindImagesByIds :many SELECT * FROM images WHERE id = ANY($1::UUID[]); -- name: FindUnusedImages :many SELECT images.* from images LEFT JOIN scene_images ON scene_images.image_id = images.id LEFT JOIN performer_images ON performer_images.image_id = images.id LEFT JOIN studio_images ON studio_images.image_id = images.id LEFT JOIN ( SELECT (jsonb_array_elements(data#>'{new_data,added_images}')->>0)::uuid AS image_id FROM edits WHERE status = 'PENDING' ) edit_images ON edit_images.image_id = images.id LEFT JOIN ( SELECT id, (data->>'image')::uuid AS image_id FROM drafts ) drafts ON images.id = drafts.image_id WHERE scene_images.scene_id IS NULL AND performer_images.performer_id IS NULL AND studio_images.studio_id IS NULL AND edit_images.image_id IS NULL AND drafts.id IS NULL LIMIT 1000; -- name: IsImageUnused :one SELECT COUNT(*) > 0 AS unused from images LEFT JOIN scene_images ON scene_images.image_id = images.id LEFT JOIN performer_images ON performer_images.image_id = images.id LEFT JOIN studio_images ON studio_images.image_id = images.id LEFT JOIN ( SELECT (jsonb_array_elements(data#>'{new_data,added_images}')->>0)::uuid AS image_id FROM edits WHERE status = 'PENDING' ) edit_images ON edit_images.image_id = images.id LEFT JOIN ( SELECT id, (data->>'image')::uuid AS image_id FROM drafts ) drafts ON images.id = drafts.image_id WHERE images.id = $1 AND scene_images.scene_id IS NULL AND performer_images.performer_id IS NULL AND studio_images.studio_id IS NULL AND edit_images.image_id IS NULL AND drafts.id IS NULL; -- name: FindImageIdsBySceneIds :many SELECT scene_images.scene_id, scene_images.image_id FROM scene_images WHERE scene_images.scene_id = ANY($1::UUID[]); -- name: FindImageIdsByPerformerIds :many SELECT performer_images.performer_id, performer_images.image_id FROM performer_images WHERE performer_images.performer_id = ANY($1::UUID[]); -- name: FindImageIdsByStudioIds :many SELECT studio_images.studio_id, studio_images.image_id FROM studio_images WHERE studio_images.studio_id = ANY($1::UUID[]); ================================================ FILE: internal/queries/sql/invite_key.sql ================================================ -- Invite key queries -- name: CreateInviteKey :one INSERT INTO invite_keys (id, generated_by, uses, expire_time, generated_at) VALUES ($1, $2, $3, $4, now()) RETURNING *; -- name: DeleteInviteKey :exec DELETE FROM invite_keys WHERE id = $1; -- name: FindInviteKey :one SELECT * FROM invite_keys WHERE id = $1; -- name: FindActiveInviteKeysForUser :many SELECT i.* FROM invite_keys i LEFT JOIN ( SELECT uuid(data->>'invite_key') as invite_key, COUNT(*) as count FROM user_tokens WHERE expires_at > NOW() GROUP BY data->>'invite_key' ) AS used ON used.invite_key = i.id WHERE i.generated_by = $1 AND (i.expire_time IS NULL OR i.expire_time > NOW()) AND (used.invite_key IS NULL OR i.uses IS NULL OR used.count < i.uses); -- name: InviteKeyUsed :one UPDATE invite_keys SET uses = GREATEST(0, uses - 1) WHERE id = $1 AND uses IS NOT NULL AND uses > 0 RETURNING uses; -- name: DestroyExpiredInvites :exec DELETE FROM invite_keys WHERE expire_time IS NOT NULL AND expire_time < NOW(); ================================================ FILE: internal/queries/sql/mod_audit.sql ================================================ -- name: CreateModAudit :one INSERT INTO mod_audit ( id, action, user_id, target_id, target_type, data, reason, created_at ) VALUES ($1, $2, $3, $4, $5, $6, $7, NOW()) RETURNING *; -- name: GetModAuditCount :one SELECT COUNT(*) FROM mod_audit WHERE (sqlc.narg('action')::mod_audit_action IS NULL OR action = sqlc.narg('action')) AND (sqlc.narg('user_id')::uuid IS NULL OR user_id = sqlc.narg('user_id')); -- name: QueryModAudits :many SELECT * FROM mod_audit WHERE (sqlc.narg('action')::mod_audit_action IS NULL OR action = sqlc.narg('action')) AND (sqlc.narg('user_id')::uuid IS NULL OR user_id = sqlc.narg('user_id')) ORDER BY created_at DESC LIMIT $1 OFFSET $2; -- name: DeleteExpiredModAudits :exec DELETE FROM mod_audit WHERE created_at < NOW() - INTERVAL '1 day' * $1; ================================================ FILE: internal/queries/sql/notification.sql ================================================ -- Notification queries -- name: FindNotificationsByUser :many SELECT * FROM notifications WHERE user_id = $1 AND (sqlc.narg(type)::notification_type IS NULL OR type = sqlc.narg(type)::notification_type) ORDER BY created_at DESC LIMIT $2 OFFSET $3; -- name: FindUnreadNotificationsByUser :many SELECT * FROM notifications WHERE user_id = $1 AND read_at IS NULL AND (sqlc.narg(type)::notification_type IS NULL OR type = sqlc.narg(type)::notification_type) ORDER BY created_at DESC LIMIT $2 OFFSET $3; -- name: CountNotificationsByUser :one SELECT COUNT(*) FROM notifications WHERE user_id = $1 AND (sqlc.arg(unread_only)::boolean = FALSE OR read_at IS NULL) AND (sqlc.narg(type)::notification_type IS NULL OR type = sqlc.narg(type)::notification_type); -- name: MarkAllNotificationsRead :exec UPDATE notifications SET read_at = NOW() WHERE user_id = $1 AND read_at IS NULL; -- name: MarkNotificationRead :exec UPDATE notifications SET read_at = NOW() WHERE user_id = $1 AND type = $2 AND id = $3 AND read_at IS NULL; -- User notification subscriptions -- name: CreateUserNotificationSubscriptions :copyfrom INSERT INTO user_notifications (user_id, type) VALUES ($1, $2); -- name: DeleteUserNotificationSubscriptions :exec DELETE FROM user_notifications WHERE user_id = $1; -- name: DestroyExpiredNotifications :exec DELETE FROM notifications WHERE read_at < CURRENT_DATE - INTERVAL '1 day' OR created_at < CURRENT_DATE - INTERVAL '14 day'; -- name: TriggerSceneCreationNotifications :exec INSERT INTO notifications (user_id, type, id) SELECT N.user_id, N.type, $1 as id FROM scenes S JOIN scene_edits SE ON S.id = SE.scene_id JOIN edits E ON SE.edit_id = E.id AND E.operation = 'CREATE' JOIN studio_favorites SF ON S.studio_id = SF.studio_id JOIN user_notifications N ON SF.user_id = N.user_id AND N.type = 'FAVORITE_STUDIO_SCENE' AND E.user_id != N.user_id WHERE S.id = $1 UNION SELECT N.user_id, N.type, $1 as id FROM scene_performers SP JOIN scene_edits SE ON SP.scene_id = SE.scene_id JOIN edits E ON SE.edit_id = E.id AND E.operation = 'CREATE' JOIN performer_favorites PF ON SP.performer_id = PF.performer_id JOIN user_notifications N ON PF.user_id = N.user_id AND N.type = 'FAVORITE_PERFORMER_SCENE' AND E.user_id != N.user_id WHERE SP.scene_id = $1; -- name: TriggerPerformerEditNotifications :exec INSERT INTO notifications (user_id, type, id) SELECT N.user_id, N.type, $1 FROM performer_edits PE JOIN edits E ON PE.edit_id = E.id JOIN performer_favorites PF ON PE.performer_id = PF.performer_id JOIN user_notifications N ON PF.user_id = N.user_id AND N.type = 'FAVORITE_PERFORMER_EDIT' AND N.user_id != E.user_id WHERE PE.edit_id = $1; -- name: TriggerStudioEditNotifications :exec INSERT INTO notifications (user_id, type, id) SELECT N.user_id, N.type, $1 FROM studio_edits SE JOIN edits E ON SE.edit_id = E.id JOIN studio_favorites SF ON SE.studio_id = SF.studio_id JOIN user_notifications N ON SF.user_id = N.user_id AND N.type = 'FAVORITE_STUDIO_EDIT' AND N.user_id != E.user_id WHERE SE.edit_id = $1; -- name: TriggerDownvoteEditNotifications :exec INSERT INTO notifications (user_id, type, id) SELECT N.user_id, N.type, $1 FROM edits E JOIN user_notifications N ON E.user_id = N.user_id AND N.type = 'DOWNVOTE_OWN_EDIT' WHERE E.id = $1; -- name: TriggerFailedEditNotifications :exec INSERT INTO notifications (user_id, type, id) SELECT N.user_id, N.type, $1 FROM edits E JOIN user_notifications N ON E.user_id = N.user_id AND N.type = 'FAILED_OWN_EDIT' WHERE E.id = $1; -- name: TriggerUpdatedEditNotifications :exec INSERT INTO notifications (user_id, type, id) SELECT N.user_id, N.type, $1 FROM edits E JOIN edit_votes EV ON E.id = EV.edit_id JOIN user_notifications N ON EV.user_id = N.user_id AND N.type = 'UPDATED_EDIT' WHERE E.id = $1; -- name: TriggerSceneEditNotifications :exec INSERT INTO notifications (user_id, type, id) SELECT DISTINCT ON (user_id) user_id, type, $1 FROM ( SELECT N.user_id, N.type FROM edits E JOIN studio_favorites SF ON (E.data->'new_data'->>'studio_id')::uuid = SF.studio_id JOIN user_notifications N ON SF.user_id = N.user_id AND N.type = 'FAVORITE_STUDIO_EDIT' AND N.user_id != E.user_id WHERE E.id = $1 UNION SELECT N.user_id, N.type FROM edits E JOIN scene_edits SE ON E.id = SE.edit_id JOIN scenes S ON SE.scene_id = S.id JOIN studio_favorites SF ON S.studio_id = SF.studio_id JOIN user_notifications N ON SF.user_id = N.user_id AND N.type = 'FAVORITE_STUDIO_EDIT' AND N.user_id != E.user_id WHERE E.id = $1 UNION SELECT N.user_id, N.type FROM ( SELECT id, (jsonb_array_elements(edits.data->'new_data'->'added_performers')->>'performer_id')::uuid AS performer_id, user_id FROM edits ) E JOIN performer_favorites PF ON E.performer_id = PF.performer_id JOIN user_notifications N ON PF.user_id = N.user_id AND N.type = 'FAVORITE_PERFORMER_EDIT' AND N.user_id != E.user_id WHERE E.id = $1 UNION SELECT N.user_id, N.type FROM edits E JOIN scene_edits SE ON E.id = SE.edit_id JOIN scene_performers SP ON SP.scene_id = SE.scene_id JOIN performer_favorites PF ON PF.performer_id = SP.performer_id JOIN user_notifications N ON PF.user_id = N.user_id AND N.type = 'FAVORITE_PERFORMER_EDIT' AND N.user_id != E.user_id WHERE E.id = $1 UNION SELECT N.user_id, N.type FROM edits E JOIN scene_edits SE ON E.id = SE.edit_id JOIN scene_fingerprints SF ON SE.scene_id = SF.scene_id JOIN user_notifications N ON SF.user_id = N.user_id AND N.type = 'FINGERPRINTED_SCENE_EDIT' AND N.user_id != E.user_id WHERE E.id = $1 ) notifications; -- name: TriggerEditCommentNotifications :exec INSERT INTO notifications (user_id, type, id) SELECT DISTINCT ON (user_id) user_id, type, $1 FROM ( SELECT N.user_id, N.type, 1 as ordering FROM edit_comments EC JOIN edits E ON EC.edit_id = E.id JOIN user_notifications N ON E.user_id = N.user_id AND N.type = 'COMMENT_OWN_EDIT' WHERE E.user_id != EC.user_id AND EC.id = $1 UNION SELECT N.user_id, N.type, 2 as ordering FROM edit_comments EC JOIN edits E ON EC.edit_id = E.id JOIN edit_comments EO ON EO.edit_id = E.id JOIN user_notifications N ON EO.user_id = N.user_id AND N.type = 'COMMENT_COMMENTED_EDIT' WHERE EO.user_id != E.user_id AND EO.user_id != EC.user_id AND EC.id = $1 UNION SELECT N.user_id, N.type, 3 as ordering FROM edit_comments EC JOIN edits E ON EC.edit_id = E.id JOIN edit_votes EV ON EV.edit_id = E.id JOIN user_notifications N ON EV.user_id = N.user_id AND N.type = 'COMMENT_VOTED_EDIT' WHERE EV.vote != 'ABSTAIN' AND EV.user_id != E.user_id AND EV.user_id != EC.user_id AND EC.id = $1 ) notifications ORDER BY user_id, ordering ASC; ================================================ FILE: internal/queries/sql/performer.sql ================================================ -- Performer queries -- name: CreatePerformer :one INSERT INTO performers ( id, name, disambiguation, gender, birthdate, ethnicity, country, eye_color, hair_color, height, cup_size, band_size, hip_size, waist_size, breast_type, career_start_year, career_end_year, deathdate, created_at, updated_at ) VALUES ( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, now(), now() ) RETURNING *; -- name: UpdatePerformer :one UPDATE performers SET name = $2, disambiguation = $3, gender = $4, birthdate = $5, ethnicity = $6, country = $7, eye_color = $8, hair_color = $9, height = $10, cup_size = $11, band_size = $12, hip_size = $13, waist_size = $14, breast_type = $15, career_start_year = $16, career_end_year = $17, deathdate = $18, updated_at = now() WHERE id = $1 RETURNING *; -- name: DeletePerformer :exec DELETE FROM performers WHERE id = $1; -- name: SoftDeletePerformer :one UPDATE performers SET deleted = true, updated_at = NOW() WHERE id = $1 RETURNING *; -- name: FindPerformer :one SELECT * FROM performers WHERE id = $1; -- name: FindPerformerWithRedirect :many SELECT P.* FROM performers P WHERE P.id = $1 AND P.deleted = FALSE UNION SELECT T.* FROM performer_redirects R JOIN performers T ON T.id = R.target_id WHERE R.source_id = $1 AND T.deleted = FALSE; -- name: FindPerformersByIds :many SELECT * FROM performers WHERE id = ANY($1::UUID[]); -- name: FindPerformerByName :one SELECT * FROM performers WHERE UPPER(name) = UPPER($1) AND deleted = false; -- name: FindExistingPerformers :many SELECT * FROM performers WHERE ( (sqlc.narg('name')::text IS NOT NULL AND TRIM(LOWER(name)) = TRIM(LOWER(sqlc.narg('name'))) AND CASE WHEN sqlc.narg('disambiguation')::text IS NOT NULL THEN TRIM(LOWER(disambiguation)) = TRIM(LOWER(sqlc.narg('disambiguation'))) ELSE (disambiguation IS NULL OR disambiguation = '') END) OR (sqlc.narg('urls')::text[] IS NOT NULL AND id IN ( SELECT performer_id FROM performer_urls WHERE url = ANY(sqlc.narg('urls')) GROUP BY performer_id )) ); -- name: FindPerformersByURL :many SELECT P.* FROM performers P JOIN performer_urls PU ON PU.performer_id = P.id WHERE LOWER(PU.url) = LOWER(sqlc.narg('url')) LIMIT sqlc.arg('limit'); -- name: SearchPerformersWithFacets :many SELECT performer_id, pdb.agg('{"terms": {"field": "gender"}}') OVER () as gender_facets, pdb.agg('{"value_count": {"field": "performer_id"}}') OVER () as total_count FROM performer_search WHERE performer_id @@@ paradedb.disjunction_max(disjuncts => ARRAY[ paradedb.boolean( should => ARRAY[ paradedb.boost(factor => 1.5, query => paradedb.match(field => 'name', value => sqlc.narg('term')::TEXT)), paradedb.match(field => 'disambiguation', value => sqlc.narg('term')::TEXT) ] ), paradedb.match(field => 'aliases', value => sqlc.narg('term')::TEXT) ]) AND (sqlc.narg('filter_gender')::TEXT IS NULL OR gender = sqlc.narg('filter_gender')::TEXT) ORDER BY pdb.score(performer_id) DESC LIMIT sqlc.arg('limit') OFFSET sqlc.arg('offset'); -- Performer aliases -- name: DeletePerformerAliases :exec DELETE FROM performer_aliases WHERE performer_id = $1; -- name: GetPerformerAliases :many SELECT alias FROM performer_aliases WHERE performer_id = $1; -- name: FindPerformerByAlias :one SELECT p.* FROM performers p JOIN performer_aliases pa ON p.id = pa.performer_id WHERE UPPER(pa.alias) = UPPER($1) AND p.deleted = false; -- Performer URLs -- name: DeletePerformerURLs :exec DELETE FROM performer_urls WHERE performer_id = $1; -- name: GetPerformerURLs :many SELECT url, site_id FROM performer_urls WHERE performer_id = $1; -- Performer tattoos -- name: DeletePerformerTattoos :exec DELETE FROM performer_tattoos WHERE performer_id = $1; -- name: GetPerformerTattoos :many SELECT location, description FROM performer_tattoos WHERE performer_id = $1; -- Performer piercings -- name: DeletePerformerPiercings :exec DELETE FROM performer_piercings WHERE performer_id = $1; -- name: GetPerformerPiercings :many SELECT location, description FROM performer_piercings WHERE performer_id = $1; -- Performer redirects -- name: CreatePerformerRedirect :exec INSERT INTO performer_redirects (source_id, target_id) VALUES ($1, $2); -- name: UpdatePerformerRedirects :exec UPDATE performer_redirects SET target_id = @new_performer_id WHERE target_id = @old_performer_id; -- Performer favorites -- name: DeletePerformerFavorites :exec DELETE FROM performer_favorites WHERE performer_id = $1; -- name: ReassignPerformerFavorites :exec UPDATE performer_favorites SET performer_id = @new_performer_id WHERE performer_favorites.performer_id = @old_performer_id AND user_id NOT IN ( SELECT user_id FROM performer_favorites PF WHERE PF.performer_id = @new_performer_id ); -- name: CreatePerformerFavorite :exec INSERT INTO performer_favorites (performer_id, user_id, created_at) VALUES ($1, $2, now()); -- name: DeletePerformerFavorite :exec DELETE FROM performer_favorites WHERE performer_id = $1 AND user_id = $2; -- name: FindPerformerFavoritesByIds :many -- Check favorite status for multiple performers for a specific user SELECT performer_id, (performer_id IS NOT NULL)::BOOLEAN as is_favorite FROM performer_favorites WHERE performer_id = ANY(sqlc.arg(performer_ids)::UUID[]) AND user_id = sqlc.arg(user_id); -- Performer images -- name: GetPerformerImages :many SELECT images.* FROM images JOIN performer_images ON performer_images.image_id = images.id WHERE performer_images.performer_id = $1; -- name: DeletePerformerImages :exec DELETE FROM performer_images WHERE performer_id = $1; -- name: CreatePerformerImages :copyfrom INSERT INTO performer_images (performer_id, image_id) VALUES ($1, $2); -- name: CreatePerformerAliases :copyfrom INSERT INTO performer_aliases (performer_id, alias) VALUES ($1, $2); -- name: CreatePerformerTattoos :copyfrom INSERT INTO performer_tattoos (performer_id, location, description) VALUES ($1, $2, $3); -- name: CreatePerformerPiercings :copyfrom INSERT INTO performer_piercings (performer_id, location, description) VALUES ($1, $2, $3); -- name: CreatePerformerURLs :copyfrom INSERT INTO performer_urls (performer_id, url, site_id) VALUES ($1, $2, $3); -- name: SetScenePerformerAlias :exec UPDATE scene_performers SET "as" = $2 WHERE performer_id = $1 AND "as" IS NULL; -- name: ClearScenePerformerAlias :exec UPDATE scene_performers SET "as" = NULL WHERE performer_id = $1 AND "as" = $2; -- name: ReassignPerformerAliases :exec UPDATE scene_performers SET performer_id = @new_performer_id WHERE scene_performers.performer_id = @old_performer_id AND scene_id NOT IN (SELECT scene_id from scene_performers sp WHERE sp.performer_id = @new_performer_id); -- name: DeletePerformerScenes :exec DELETE FROM scene_performers WHERE performer_id = $1; -- name: FindMergeIDsByPerformerIds :many -- Find merge target IDs for performers (for merges where these are sources) SELECT source_id as performer_id, target_id as merge_id FROM performer_redirects WHERE source_id = ANY(sqlc.arg(performer_ids)::UUID[]); -- name: FindMergeIDsBySourcePerformerIds :many -- Find merge source IDs for performers (for merges where these are targets) SELECT target_id as performer_id, source_id as merge_id FROM performer_redirects WHERE target_id = ANY(sqlc.arg(performer_ids)::UUID[]); -- name: FindPerformerAliasesByIds :many -- Get aliases for multiple performers SELECT performer_id, alias FROM performer_aliases WHERE performer_id = ANY(sqlc.arg(performer_ids)::UUID[]); -- name: FindPerformerTattoosByIds :many -- Get tattoos for multiple performers SELECT performer_id, location, description FROM performer_tattoos WHERE performer_id = ANY(sqlc.arg(performer_ids)::UUID[]); -- name: FindPerformerPiercingsByIds :many -- Get piercings for multiple performers SELECT performer_id, location, description FROM performer_piercings WHERE performer_id = ANY(sqlc.arg(performer_ids)::UUID[]); -- name: FindPerformerUrlsByIds :many -- Get URLs for multiple performers SELECT performer_id, url, site_id FROM performer_urls WHERE performer_id = ANY(sqlc.arg(performer_ids)::UUID[]); ================================================ FILE: internal/queries/sql/scene.sql ================================================ -- Scene queries -- name: CreateScene :one INSERT INTO scenes (id, title, details, date, production_date, studio_id, duration, director, code, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, now(), now()) RETURNING *; -- name: UpdateScene :one UPDATE scenes SET title = $2, details = $3, date = $4, production_date = $5, studio_id = $6, duration = $7, director = $8, code = $9, updated_at = now() WHERE id = $1 RETURNING *; -- name: DeleteScene :exec DELETE FROM scenes WHERE id = $1; -- name: SoftDeleteScene :one UPDATE scenes SET deleted = true, updated_at = NOW() WHERE id = $1 RETURNING *; -- name: DeleteSceneStudios :exec UPDATE scenes SET studio_id = NULL WHERE studio_id = $1; -- name: UpdateSceneStudios :exec UPDATE scenes SET studio_id = @target_id WHERE studio_id = @source_id; -- name: FindScene :one SELECT * FROM scenes WHERE id = $1; -- name: GetScenes :many SELECT * FROM scenes WHERE id = ANY($1::UUID[]) ORDER BY title; -- name: FindExistingScenes :many SELECT * FROM scenes WHERE ( (sqlc.narg('title')::text IS NOT NULL AND sqlc.narg('studio_id')::uuid IS NOT NULL AND TRIM(LOWER(title)) = TRIM(LOWER(sqlc.narg('title'))) AND studio_id = sqlc.narg('studio_id')) OR (sqlc.narg('hashes')::BIGINT[] IS NOT NULL AND array_length(sqlc.narg('hashes')::BIGINT[], 1) > 0 AND id IN ( SELECT scene_id FROM scene_fingerprints SFP JOIN fingerprints FP ON SFP.fingerprint_id = FP.id WHERE FP.hash = ANY(sqlc.narg('hashes')::BIGINT[]) GROUP BY scene_id )) ) AND deleted = FALSE; -- name: FindSceneByURL :many SELECT S.* FROM scenes S JOIN scene_urls SU ON SU.scene_id = S.id WHERE LOWER(SU.url) = LOWER(sqlc.narg('url')) AND S.deleted = FALSE LIMIT sqlc.arg('limit'); -- name: SearchScenes :many SELECT scene_id, pdb.agg('{"value_count": {"field": "scene_id"}}') OVER () as total_count FROM scene_search WHERE scene_id @@@ paradedb.disjunction_max(disjuncts => ARRAY[ paradedb.match(field => 'scene_title', value => sqlc.narg('term')::TEXT), paradedb.match(field => 'scene_code', value => sqlc.narg('term')::TEXT), paradedb.boolean( should => ARRAY[ paradedb.match(field => 'performer_names', value => sqlc.narg('term')::TEXT), paradedb.match(field => 'studio_name', value => sqlc.narg('term')::TEXT), paradedb.match(field => 'network_name', value => sqlc.narg('term')::TEXT) ] ) ]) ORDER BY pdb.score(scene_id) DESC LIMIT sqlc.arg('limit') OFFSET sqlc.arg('offset'); -- name: CountScenesByPerformer :one SELECT COUNT(*) FROM scene_performers WHERE performer_id = $1; -- Scene fingerprints (use fingerprint.sql for most fingerprint operations) -- name: FindScenesByFullFingerprintsWithHash :many SELECT sqlc.embed(scenes), matches.hash FROM ( SELECT SFP.scene_id AS id, FP.hash FROM UNNEST(sqlc.narg('phashes')::BIGINT[]) phash JOIN fingerprints FP ON FP.hash <@ (phash, sqlc.arg('distance')::INTEGER) AND FP.algorithm = 'PHASH' JOIN scene_fingerprints SFP ON SFP.fingerprint_id = FP.id WHERE sqlc.narg('phashes')::BIGINT[] IS NOT NULL AND array_length(sqlc.narg('phashes')::BIGINT[], 1) > 0 GROUP BY SFP.scene_id, FP.hash UNION SELECT SFP.scene_id AS id, FP.hash FROM scene_fingerprints SFP JOIN fingerprints FP ON SFP.fingerprint_id = FP.id WHERE FP.hash = ANY(sqlc.narg('hashes')::BIGINT[]) AND sqlc.narg('hashes')::BIGINT[] IS NOT NULL AND array_length(sqlc.narg('hashes')::BIGINT[], 1) > 0 GROUP BY SFP.scene_id, FP.hash ) matches JOIN scenes ON scenes.id = matches.id AND scenes.deleted = FALSE; -- Scene URLs -- name: CreateSceneURLs :copyfrom INSERT INTO scene_urls (scene_id, url, site_id) VALUES ($1, $2, $3); -- name: DeleteSceneURLs :exec DELETE FROM scene_urls WHERE scene_id = $1; -- name: GetSceneURLs :many SELECT url, site_id FROM scene_urls WHERE scene_id = $1; -- Scene performers -- name: CreateScenePerformers :copyfrom INSERT INTO scene_performers (scene_id, performer_id, "as") VALUES ($1, $2, $3); -- name: DeleteScenePerformers :exec DELETE FROM scene_performers WHERE scene_id = $1; -- name: GetScenePerformers :many SELECT sqlc.embed(P), "as" FROM scene_performers SP JOIN performers P ON SP.performer_id = P.id WHERE scene_id = $1; -- Scene images -- name: DeleteSceneImages :exec DELETE FROM scene_images WHERE scene_id = $1; -- name: CreateSceneImages :copyfrom INSERT INTO scene_images (scene_id, image_id) VALUES ($1, $2); -- Scene redirects -- name: CreateSceneRedirect :exec INSERT INTO scene_redirects (source_id, target_id) VALUES ($1, $2); -- name: UpdateSceneRedirects :exec UPDATE scene_redirects SET target_id = @new_target_id WHERE target_id = @old_target_id; -- name: FindSceneAppearancesByIds :many -- Get performer appearances for multiple scenes SELECT scene_id, performer_id, "as" FROM scene_performers WHERE scene_id = ANY(sqlc.arg(scene_ids)::UUID[]); -- name: FindSceneUrlsByIds :many -- Get URLs for multiple scenes SELECT scene_id, url, site_id FROM scene_urls WHERE scene_id = ANY(sqlc.arg(scene_ids)::UUID[]); ================================================ FILE: internal/queries/sql/site.sql ================================================ -- Site queries -- name: CreateSite :one INSERT INTO sites (id, name, description, url, regex, valid_types, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, now(), now()) RETURNING *; -- name: UpdateSite :one UPDATE sites SET name = $2, description = $3, url = $4, regex = $5, valid_types = $6, updated_at = now() WHERE id = $1 RETURNING *; -- name: DeleteSite :exec DELETE FROM sites WHERE id = $1; -- name: GetSite :one SELECT * FROM sites WHERE id = $1; -- name: FindSitesByIds :many SELECT * FROM sites WHERE id = ANY($1::UUID[]); ================================================ FILE: internal/queries/sql/studio.sql ================================================ -- Studio queries -- name: CreateStudio :one INSERT INTO studios (id, name, parent_studio_id, created_at, updated_at) VALUES ($1, $2, $3, now(), now()) RETURNING *; -- name: UpdateStudio :one UPDATE studios SET name = $2, parent_studio_id = $3, updated_at = NOW() WHERE id = $1 RETURNING *; -- name: DeleteStudio :exec DELETE FROM studios WHERE id = $1; -- name: SoftDeleteStudio :one UPDATE studios SET deleted = true, updated_at = NOW() WHERE id = $1 RETURNING *; -- name: FindStudio :one SELECT * FROM studios WHERE id = $1; -- name: GetStudios :many SELECT * FROM studios WHERE id = ANY($1::UUID[]) ORDER BY name; -- name: FindStudioByName :one SELECT * FROM studios WHERE UPPER(name) = UPPER($1) AND deleted = false; -- name: SearchStudios :many SELECT studio_id, pdb.agg('{"value_count": {"field": "studio_id"}}') OVER () as total_count FROM studio_search WHERE studio_id @@@ paradedb.boolean( should => ARRAY[ paradedb.boost(factor => 2, query => paradedb.match(field => 'name', value => sqlc.narg('term')::TEXT)), paradedb.match(field => 'network', value => sqlc.narg('term')::TEXT), paradedb.match(field => 'aliases', value => sqlc.narg('term')::TEXT) ] ) ORDER BY pdb.score(studio_id) DESC LIMIT sqlc.arg('limit'); -- name: GetStudiosByPerformer :many SELECT sqlc.embed(studios), COUNT(scenes.id) as scene_count FROM studios JOIN scenes ON studios.id = scenes.studio_id JOIN scene_performers SP ON scenes.id = SP.scene_id WHERE SP.performer_id = $1 GROUP BY studios.id; -- name: GetStudiosByPerformerAndNetwork :many -- Get studios where performer has scenes, filtered to a studio network (the studio, its parent, and children) WITH studio_network AS ( -- The studio itself SELECT sqlc.arg('studio_id')::uuid AS id UNION -- Parent studio (if exists) SELECT parent_studio_id AS id FROM studios WHERE id = sqlc.arg('studio_id') AND parent_studio_id IS NOT NULL UNION -- Child studios SELECT id FROM studios WHERE parent_studio_id = sqlc.arg('studio_id') AND deleted = FALSE ) SELECT sqlc.embed(studios), COUNT(scenes.id) as scene_count FROM studios JOIN scenes ON studios.id = scenes.studio_id JOIN scene_performers SP ON scenes.id = SP.scene_id WHERE SP.performer_id = sqlc.arg('performer_id') AND studios.id IN (SELECT id FROM studio_network WHERE id IS NOT NULL) GROUP BY studios.id; -- name: GetChildStudios :many SELECT * FROM studios WHERE parent_studio_id = $1 AND deleted = false ORDER BY name; -- Studio URLs -- name: CreateStudioURLs :copyfrom INSERT INTO studio_urls (studio_id, url, site_id) VALUES ($1, $2, $3); -- name: DeleteStudioURLs :exec DELETE FROM studio_urls WHERE studio_id = $1; -- name: GetStudioURLs :many SELECT * FROM studio_urls WHERE studio_id = $1; -- Studio images -- name: CreateStudioImages :copyfrom INSERT INTO studio_images (studio_id, image_id) VALUES ($1, $2); -- name: GetStudioImages :many SELECT image_id FROM studio_images WHERE studio_id = $1; -- name: DeleteStudioImages :exec DELETE FROM studio_images WHERE studio_id = $1; -- Studio aliases -- name: CreateStudioAliases :copyfrom INSERT INTO studio_aliases (studio_id, alias) VALUES ($1, $2); -- name: DeleteStudioAliases :exec DELETE FROM studio_aliases WHERE studio_id = $1; -- name: GetStudioAliases :many SELECT alias FROM studio_aliases WHERE studio_id = $1; -- name: FindStudioByAlias :one SELECT s.* FROM studios s JOIN studio_aliases sa ON s.id = sa.studio_id WHERE UPPER(sa.alias) = UPPER($1) AND s.deleted = false; -- Studio redirects -- name: CreateStudioRedirect :exec INSERT INTO studio_redirects (source_id, target_id) VALUES ($1, $2); -- name: UpdateStudioRedirects :exec UPDATE studio_redirects SET target_id = @new_target_id WHERE target_id = @old_target_id; -- name: FindStudioWithRedirect :one SELECT S.* FROM studios S WHERE S.id = $1 AND S.deleted = FALSE UNION SELECT SS.* FROM studio_redirects R JOIN studios SS ON SS.id = R.target_id WHERE R.source_id = $1 AND SS.deleted = FALSE; -- name: FindStudioUrlsByIds :many -- Get URLs for multiple studios SELECT studio_id, url, site_id FROM studio_urls WHERE studio_id = ANY(sqlc.arg(studio_ids)::UUID[]); -- name: FindStudioAliasesByIds :many -- Get aliases for multiple studios SELECT studio_id, alias FROM studio_aliases WHERE studio_id = ANY(sqlc.arg(studio_ids)::UUID[]); -- name: FindStudioFavoritesByIds :many -- Check favorite status for multiple studios for a specific user SELECT studio_id, (studio_id IS NOT NULL)::BOOLEAN as is_favorite FROM studio_favorites WHERE studio_id = ANY(sqlc.arg(studio_ids)::UUID[]) AND user_id = sqlc.arg(user_id); -- Studio favorites -- name: CreateStudioFavorite :exec INSERT INTO studio_favorites (studio_id, user_id, created_at) VALUES ($1, $2, NOW()); -- name: DeleteStudioFavorite :exec DELETE FROM studio_favorites WHERE studio_id = $1 AND user_id = $2; -- name: DeleteStudioFavorites :exec DELETE FROM studio_favorites WHERE studio_id = $1; -- name: ReassignStudioFavorites :exec UPDATE studio_favorites SET studio_id = @new_studio_id WHERE studio_favorites.studio_id = @old_studio_id AND user_id NOT IN ( SELECT user_id FROM studio_favorites SF WHERE SF.studio_id = @new_studio_id ); ================================================ FILE: internal/queries/sql/tag.sql ================================================ -- Tag queries -- name: CreateTag :one INSERT INTO tags (id, name, category_id, description, created_at, updated_at) VALUES ($1, $2, $3, $4, now(), now()) RETURNING *; -- name: UpdateTag :one UPDATE tags SET name = $2, category_id = $3, description = $4, updated_at = NOW() WHERE id = $1 RETURNING *; -- name: DeleteTag :exec DELETE FROM tags WHERE id = $1; -- name: SoftDeleteTag :one UPDATE tags SET deleted = true, updated_at = NOW() WHERE id = $1 RETURNING *; -- name: FindTag :one SELECT * FROM tags WHERE id = $1; -- name: FindTagByName :one SELECT * FROM tags WHERE UPPER(name) = UPPER($1) AND deleted = false; -- name: SearchTags :many SELECT T.* FROM tags T JOIN tag_search TS ON TS.tag_id = T.id WHERE TS.tag_id @@@ paradedb.boolean(should => ARRAY[ paradedb.fuzzy_term(field => 'name', value => sqlc.narg('term')::TEXT, distance => 1, prefix => true), paradedb.fuzzy_term(field => 'aliases', value => sqlc.narg('term')::TEXT, distance => 1, prefix => true) ]) AND T.deleted = FALSE ORDER BY paradedb.score(TS.tag_id) DESC LIMIT sqlc.arg('limit'); -- name: FindTagsByIds :many SELECT * FROM tags WHERE id = ANY($1::UUID[]); -- Tag aliases -- name: CreateTagAliases :copyfrom INSERT INTO tag_aliases (tag_id, alias) VALUES ($1, $2); -- name: DeleteTagAliases :exec DELETE FROM tag_aliases WHERE tag_id = $1; -- name: DeleteTagAliasesByNames :exec DELETE FROM tag_aliases WHERE tag_id = $1 AND alias = ANY($2::TEXT[]); -- name: GetTagAliases :many SELECT alias FROM tag_aliases WHERE tag_id = $1; -- name: FindTagByAlias :one SELECT t.* FROM tags t JOIN tag_aliases ta ON t.id = ta.tag_id WHERE UPPER(ta.alias) = UPPER($1) AND t.deleted = false; -- name: FindTagByNameOrAlias :one SELECT T.* FROM tags T LEFT JOIN tag_aliases TA ON T.id = TA.tag_id WHERE ( LOWER(TA.alias) = LOWER($1) OR LOWER(T.name) = LOWER($1) ) AND T.deleted = FALSE; -- Tag redirects -- name: CreateTagRedirect :exec INSERT INTO tag_redirects (source_id, target_id) VALUES ($1, $2); -- name: UpdateTagRedirects :exec UPDATE tag_redirects SET target_id = @new_target_id WHERE target_id = @old_target_id; -- name: FindTagWithRedirect :many SELECT T.* FROM tags T WHERE T.id = $1 AND T.deleted = FALSE UNION SELECT TT.* FROM tag_redirects R JOIN tags TT ON TT.id = R.target_id WHERE R.source_id = $1 AND TT.deleted = FALSE; -- Scene tags management -- name: CreateSceneTags :copyfrom INSERT INTO scene_tags (scene_id, tag_id) VALUES ($1, $2); -- name: DeleteSceneTagsByTag :exec DELETE FROM scene_tags WHERE tag_id = $1; -- name: DeleteSceneTagsByScene :exec DELETE FROM scene_tags WHERE scene_id = $1; -- name: GetSceneTags :many SELECT T.* FROM scene_tags ST JOIN tags T ON ST.tag_id = T.id WHERE scene_id = $1; -- name: FindTagsBySceneID :many SELECT t.* FROM tags t INNER JOIN scene_tags st ON st.tag_id = t.id WHERE st.scene_id = $1; -- name: UpdateSceneTagsForMerge :exec UPDATE scene_tags SET tag_id = @new_tag_id WHERE scene_tags.tag_id = @old_tag_id AND scene_id NOT IN (SELECT scene_id from scene_tags st WHERE st.tag_id = @new_tag_id); -- name: FindTagIdsBySceneIds :many -- Bulk query to find tag IDs for multiple scene IDs SELECT scene_id, tag_id FROM scene_tags WHERE scene_id = ANY(sqlc.arg(scene_ids)::UUID[]); ================================================ FILE: internal/queries/sql/tag_category.sql ================================================ -- Tag category queries -- name: CreateTagCategory :one INSERT INTO tag_categories (id, "group", name, description, created_at, updated_at) VALUES ($1, $2, $3, $4, now(), now()) RETURNING *; -- name: UpdateTagCategory :one UPDATE tag_categories SET "group" = $2, name = $3, description = $4, updated_at = now() WHERE id = $1 RETURNING *; -- name: DeleteTagCategory :exec DELETE FROM tag_categories WHERE id = $1; -- name: FindTagCategory :one SELECT * FROM tag_categories WHERE id = $1; -- name: GetAllTagCategories :many SELECT * FROM tag_categories ORDER BY name ASC; -- name: GetTagCategoriesByIds :many SELECT * FROM tag_categories WHERE id = ANY($1::UUID[]); ================================================ FILE: internal/queries/sql/user.sql ================================================ -- User queries -- name: CreateUser :one INSERT INTO users (id, name, password_hash, email, api_key, api_calls, invite_tokens, invited_by, last_api_call, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, NOW(), NOW(), NOW()) RETURNING *; -- name: UpdateUser :one UPDATE users SET name = $2, password_hash = $3, email = $4, updated_at = NOW() WHERE id = $1 RETURNING *; -- name: DeleteUser :exec DELETE FROM users WHERE id = $1; -- name: FindUser :one SELECT * FROM users WHERE id = $1; -- name: FindUserByName :one SELECT * FROM users WHERE UPPER(name) = UPPER(sqlc.arg(name)::text); -- name: FindUserByEmail :one SELECT * FROM users WHERE UPPER(email) = UPPER($1); -- name: CountUsers :one SELECT COUNT(*) FROM users; -- name: UpdateUserAPIKey :exec UPDATE users SET api_key = $2, updated_at = NOW() WHERE id = $1; -- name: UpdateUserPassword :exec UPDATE users SET password_hash = $2, updated_at = NOW() WHERE id = $1; -- name: UpdateUserInviteTokenCount :exec UPDATE users SET invite_tokens = $2 WHERE id = $1; -- name: UpdateUserEmail :exec UPDATE users SET email = $2, updated_at = NOW() WHERE id = $1; -- User roles -- name: CreateUserRoles :copyfrom INSERT INTO user_roles (user_id, role) VALUES ($1, $2); -- name: DeleteUserRoles :exec DELETE FROM user_roles WHERE user_id = $1; -- name: GetUserRoles :many SELECT role FROM user_roles WHERE user_id = $1; -- name: CountVotesByType :many SELECT vote, COUNT(*) as count FROM edit_votes WHERE user_id = $1 GROUP BY vote; -- name: CountUserEditsByStatus :many SELECT status, COUNT(*) as count FROM edits WHERE user_id = $1 GROUP BY status; -- name: GetUserNotificationSubscriptions :many SELECT type FROM user_notifications WHERE user_id = $1; ================================================ FILE: internal/queries/sql/user_token.sql ================================================ -- User token queries -- name: CreateUserToken :one INSERT INTO user_tokens (id, data, type, created_at, expires_at) VALUES ($1, $2, $3, $4, $5) RETURNING *; -- name: DeleteUserToken :exec DELETE FROM user_tokens WHERE id = $1; -- name: DeleteExpiredUserTokens :exec DELETE FROM user_tokens WHERE expires_at <= now(); -- name: FindUserToken :one SELECT * FROM user_tokens WHERE id = $1; -- name: FindUserTokensByInviteKey :many SELECT * FROM user_tokens WHERE (data->>'invite_key')::UUID = $1::UUID; -- name: FindUserTokensByEmail :many SELECT * FROM user_tokens WHERE data->>'email' = $1::text; ================================================ FILE: internal/queries/studio.sql.go ================================================ // Code generated by sqlc. DO NOT EDIT. // versions: // sqlc v1.29.0 // source: studio.sql package queries import ( "context" "github.com/gofrs/uuid" ) const createStudio = `-- name: CreateStudio :one INSERT INTO studios (id, name, parent_studio_id, created_at, updated_at) VALUES ($1, $2, $3, now(), now()) RETURNING id, name, parent_studio_id, created_at, updated_at, deleted ` type CreateStudioParams struct { ID uuid.UUID `db:"id" json:"id"` Name string `db:"name" json:"name"` ParentStudioID uuid.NullUUID `db:"parent_studio_id" json:"parent_studio_id"` } // Studio queries func (q *Queries) CreateStudio(ctx context.Context, arg CreateStudioParams) (Studio, error) { row := q.db.QueryRow(ctx, createStudio, arg.ID, arg.Name, arg.ParentStudioID) var i Studio err := row.Scan( &i.ID, &i.Name, &i.ParentStudioID, &i.CreatedAt, &i.UpdatedAt, &i.Deleted, ) return i, err } type CreateStudioAliasesParams struct { StudioID uuid.UUID `db:"studio_id" json:"studio_id"` Alias string `db:"alias" json:"alias"` } const createStudioFavorite = `-- name: CreateStudioFavorite :exec INSERT INTO studio_favorites (studio_id, user_id, created_at) VALUES ($1, $2, NOW()) ` type CreateStudioFavoriteParams struct { StudioID uuid.UUID `db:"studio_id" json:"studio_id"` UserID uuid.UUID `db:"user_id" json:"user_id"` } // Studio favorites func (q *Queries) CreateStudioFavorite(ctx context.Context, arg CreateStudioFavoriteParams) error { _, err := q.db.Exec(ctx, createStudioFavorite, arg.StudioID, arg.UserID) return err } type CreateStudioImagesParams struct { StudioID uuid.UUID `db:"studio_id" json:"studio_id"` ImageID uuid.UUID `db:"image_id" json:"image_id"` } const createStudioRedirect = `-- name: CreateStudioRedirect :exec INSERT INTO studio_redirects (source_id, target_id) VALUES ($1, $2) ` type CreateStudioRedirectParams struct { SourceID uuid.UUID `db:"source_id" json:"source_id"` TargetID uuid.UUID `db:"target_id" json:"target_id"` } // Studio redirects func (q *Queries) CreateStudioRedirect(ctx context.Context, arg CreateStudioRedirectParams) error { _, err := q.db.Exec(ctx, createStudioRedirect, arg.SourceID, arg.TargetID) return err } type CreateStudioURLsParams struct { StudioID uuid.UUID `db:"studio_id" json:"studio_id"` Url string `db:"url" json:"url"` SiteID uuid.UUID `db:"site_id" json:"site_id"` } const deleteStudio = `-- name: DeleteStudio :exec DELETE FROM studios WHERE id = $1 ` func (q *Queries) DeleteStudio(ctx context.Context, id uuid.UUID) error { _, err := q.db.Exec(ctx, deleteStudio, id) return err } const deleteStudioAliases = `-- name: DeleteStudioAliases :exec DELETE FROM studio_aliases WHERE studio_id = $1 ` func (q *Queries) DeleteStudioAliases(ctx context.Context, studioID uuid.UUID) error { _, err := q.db.Exec(ctx, deleteStudioAliases, studioID) return err } const deleteStudioFavorite = `-- name: DeleteStudioFavorite :exec DELETE FROM studio_favorites WHERE studio_id = $1 AND user_id = $2 ` type DeleteStudioFavoriteParams struct { StudioID uuid.UUID `db:"studio_id" json:"studio_id"` UserID uuid.UUID `db:"user_id" json:"user_id"` } func (q *Queries) DeleteStudioFavorite(ctx context.Context, arg DeleteStudioFavoriteParams) error { _, err := q.db.Exec(ctx, deleteStudioFavorite, arg.StudioID, arg.UserID) return err } const deleteStudioFavorites = `-- name: DeleteStudioFavorites :exec DELETE FROM studio_favorites WHERE studio_id = $1 ` func (q *Queries) DeleteStudioFavorites(ctx context.Context, studioID uuid.UUID) error { _, err := q.db.Exec(ctx, deleteStudioFavorites, studioID) return err } const deleteStudioImages = `-- name: DeleteStudioImages :exec DELETE FROM studio_images WHERE studio_id = $1 ` func (q *Queries) DeleteStudioImages(ctx context.Context, studioID uuid.UUID) error { _, err := q.db.Exec(ctx, deleteStudioImages, studioID) return err } const deleteStudioURLs = `-- name: DeleteStudioURLs :exec DELETE FROM studio_urls WHERE studio_id = $1 ` func (q *Queries) DeleteStudioURLs(ctx context.Context, studioID uuid.UUID) error { _, err := q.db.Exec(ctx, deleteStudioURLs, studioID) return err } const findStudio = `-- name: FindStudio :one SELECT id, name, parent_studio_id, created_at, updated_at, deleted FROM studios WHERE id = $1 ` func (q *Queries) FindStudio(ctx context.Context, id uuid.UUID) (Studio, error) { row := q.db.QueryRow(ctx, findStudio, id) var i Studio err := row.Scan( &i.ID, &i.Name, &i.ParentStudioID, &i.CreatedAt, &i.UpdatedAt, &i.Deleted, ) return i, err } const findStudioAliasesByIds = `-- name: FindStudioAliasesByIds :many SELECT studio_id, alias FROM studio_aliases WHERE studio_id = ANY($1::UUID[]) ` // Get aliases for multiple studios func (q *Queries) FindStudioAliasesByIds(ctx context.Context, studioIds []uuid.UUID) ([]StudioAlias, error) { rows, err := q.db.Query(ctx, findStudioAliasesByIds, studioIds) if err != nil { return nil, err } defer rows.Close() items := []StudioAlias{} for rows.Next() { var i StudioAlias if err := rows.Scan(&i.StudioID, &i.Alias); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const findStudioByAlias = `-- name: FindStudioByAlias :one SELECT s.id, s.name, s.parent_studio_id, s.created_at, s.updated_at, s.deleted FROM studios s JOIN studio_aliases sa ON s.id = sa.studio_id WHERE UPPER(sa.alias) = UPPER($1) AND s.deleted = false ` func (q *Queries) FindStudioByAlias(ctx context.Context, upper interface{}) (Studio, error) { row := q.db.QueryRow(ctx, findStudioByAlias, upper) var i Studio err := row.Scan( &i.ID, &i.Name, &i.ParentStudioID, &i.CreatedAt, &i.UpdatedAt, &i.Deleted, ) return i, err } const findStudioByName = `-- name: FindStudioByName :one SELECT id, name, parent_studio_id, created_at, updated_at, deleted FROM studios WHERE UPPER(name) = UPPER($1) AND deleted = false ` func (q *Queries) FindStudioByName(ctx context.Context, upper interface{}) (Studio, error) { row := q.db.QueryRow(ctx, findStudioByName, upper) var i Studio err := row.Scan( &i.ID, &i.Name, &i.ParentStudioID, &i.CreatedAt, &i.UpdatedAt, &i.Deleted, ) return i, err } const findStudioFavoritesByIds = `-- name: FindStudioFavoritesByIds :many SELECT studio_id, (studio_id IS NOT NULL)::BOOLEAN as is_favorite FROM studio_favorites WHERE studio_id = ANY($1::UUID[]) AND user_id = $2 ` type FindStudioFavoritesByIdsParams struct { StudioIds []uuid.UUID `db:"studio_ids" json:"studio_ids"` UserID uuid.UUID `db:"user_id" json:"user_id"` } type FindStudioFavoritesByIdsRow struct { StudioID uuid.UUID `db:"studio_id" json:"studio_id"` IsFavorite bool `db:"is_favorite" json:"is_favorite"` } // Check favorite status for multiple studios for a specific user func (q *Queries) FindStudioFavoritesByIds(ctx context.Context, arg FindStudioFavoritesByIdsParams) ([]FindStudioFavoritesByIdsRow, error) { rows, err := q.db.Query(ctx, findStudioFavoritesByIds, arg.StudioIds, arg.UserID) if err != nil { return nil, err } defer rows.Close() items := []FindStudioFavoritesByIdsRow{} for rows.Next() { var i FindStudioFavoritesByIdsRow if err := rows.Scan(&i.StudioID, &i.IsFavorite); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const findStudioUrlsByIds = `-- name: FindStudioUrlsByIds :many SELECT studio_id, url, site_id FROM studio_urls WHERE studio_id = ANY($1::UUID[]) ` // Get URLs for multiple studios func (q *Queries) FindStudioUrlsByIds(ctx context.Context, studioIds []uuid.UUID) ([]StudioUrl, error) { rows, err := q.db.Query(ctx, findStudioUrlsByIds, studioIds) if err != nil { return nil, err } defer rows.Close() items := []StudioUrl{} for rows.Next() { var i StudioUrl if err := rows.Scan(&i.StudioID, &i.Url, &i.SiteID); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const findStudioWithRedirect = `-- name: FindStudioWithRedirect :one SELECT s.id, s.name, s.parent_studio_id, s.created_at, s.updated_at, s.deleted FROM studios S WHERE S.id = $1 AND S.deleted = FALSE UNION SELECT ss.id, ss.name, ss.parent_studio_id, ss.created_at, ss.updated_at, ss.deleted FROM studio_redirects R JOIN studios SS ON SS.id = R.target_id WHERE R.source_id = $1 AND SS.deleted = FALSE ` func (q *Queries) FindStudioWithRedirect(ctx context.Context, id uuid.UUID) (Studio, error) { row := q.db.QueryRow(ctx, findStudioWithRedirect, id) var i Studio err := row.Scan( &i.ID, &i.Name, &i.ParentStudioID, &i.CreatedAt, &i.UpdatedAt, &i.Deleted, ) return i, err } const getChildStudios = `-- name: GetChildStudios :many SELECT id, name, parent_studio_id, created_at, updated_at, deleted FROM studios WHERE parent_studio_id = $1 AND deleted = false ORDER BY name ` func (q *Queries) GetChildStudios(ctx context.Context, parentStudioID uuid.NullUUID) ([]Studio, error) { rows, err := q.db.Query(ctx, getChildStudios, parentStudioID) if err != nil { return nil, err } defer rows.Close() items := []Studio{} for rows.Next() { var i Studio if err := rows.Scan( &i.ID, &i.Name, &i.ParentStudioID, &i.CreatedAt, &i.UpdatedAt, &i.Deleted, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getStudioAliases = `-- name: GetStudioAliases :many SELECT alias FROM studio_aliases WHERE studio_id = $1 ` func (q *Queries) GetStudioAliases(ctx context.Context, studioID uuid.UUID) ([]string, error) { rows, err := q.db.Query(ctx, getStudioAliases, studioID) if err != nil { return nil, err } defer rows.Close() items := []string{} for rows.Next() { var alias string if err := rows.Scan(&alias); err != nil { return nil, err } items = append(items, alias) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getStudioImages = `-- name: GetStudioImages :many SELECT image_id FROM studio_images WHERE studio_id = $1 ` func (q *Queries) GetStudioImages(ctx context.Context, studioID uuid.UUID) ([]uuid.UUID, error) { rows, err := q.db.Query(ctx, getStudioImages, studioID) if err != nil { return nil, err } defer rows.Close() items := []uuid.UUID{} for rows.Next() { var image_id uuid.UUID if err := rows.Scan(&image_id); err != nil { return nil, err } items = append(items, image_id) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getStudioURLs = `-- name: GetStudioURLs :many SELECT studio_id, url, site_id FROM studio_urls WHERE studio_id = $1 ` func (q *Queries) GetStudioURLs(ctx context.Context, studioID uuid.UUID) ([]StudioUrl, error) { rows, err := q.db.Query(ctx, getStudioURLs, studioID) if err != nil { return nil, err } defer rows.Close() items := []StudioUrl{} for rows.Next() { var i StudioUrl if err := rows.Scan(&i.StudioID, &i.Url, &i.SiteID); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getStudios = `-- name: GetStudios :many SELECT id, name, parent_studio_id, created_at, updated_at, deleted FROM studios WHERE id = ANY($1::UUID[]) ORDER BY name ` func (q *Queries) GetStudios(ctx context.Context, dollar_1 []uuid.UUID) ([]Studio, error) { rows, err := q.db.Query(ctx, getStudios, dollar_1) if err != nil { return nil, err } defer rows.Close() items := []Studio{} for rows.Next() { var i Studio if err := rows.Scan( &i.ID, &i.Name, &i.ParentStudioID, &i.CreatedAt, &i.UpdatedAt, &i.Deleted, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getStudiosByPerformer = `-- name: GetStudiosByPerformer :many SELECT studios.id, studios.name, studios.parent_studio_id, studios.created_at, studios.updated_at, studios.deleted, COUNT(scenes.id) as scene_count FROM studios JOIN scenes ON studios.id = scenes.studio_id JOIN scene_performers SP ON scenes.id = SP.scene_id WHERE SP.performer_id = $1 GROUP BY studios.id ` type GetStudiosByPerformerRow struct { Studio Studio `db:"studio" json:"studio"` SceneCount int64 `db:"scene_count" json:"scene_count"` } func (q *Queries) GetStudiosByPerformer(ctx context.Context, performerID uuid.UUID) ([]GetStudiosByPerformerRow, error) { rows, err := q.db.Query(ctx, getStudiosByPerformer, performerID) if err != nil { return nil, err } defer rows.Close() items := []GetStudiosByPerformerRow{} for rows.Next() { var i GetStudiosByPerformerRow if err := rows.Scan( &i.Studio.ID, &i.Studio.Name, &i.Studio.ParentStudioID, &i.Studio.CreatedAt, &i.Studio.UpdatedAt, &i.Studio.Deleted, &i.SceneCount, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getStudiosByPerformerAndNetwork = `-- name: GetStudiosByPerformerAndNetwork :many WITH studio_network AS ( -- The studio itself SELECT $2::uuid AS id UNION -- Parent studio (if exists) SELECT parent_studio_id AS id FROM studios WHERE id = $2 AND parent_studio_id IS NOT NULL UNION -- Child studios SELECT id FROM studios WHERE parent_studio_id = $2 AND deleted = FALSE ) SELECT studios.id, studios.name, studios.parent_studio_id, studios.created_at, studios.updated_at, studios.deleted, COUNT(scenes.id) as scene_count FROM studios JOIN scenes ON studios.id = scenes.studio_id JOIN scene_performers SP ON scenes.id = SP.scene_id WHERE SP.performer_id = $1 AND studios.id IN (SELECT id FROM studio_network WHERE id IS NOT NULL) GROUP BY studios.id ` type GetStudiosByPerformerAndNetworkParams struct { PerformerID uuid.UUID `db:"performer_id" json:"performer_id"` StudioID uuid.UUID `db:"studio_id" json:"studio_id"` } type GetStudiosByPerformerAndNetworkRow struct { Studio Studio `db:"studio" json:"studio"` SceneCount int64 `db:"scene_count" json:"scene_count"` } // Get studios where performer has scenes, filtered to a studio network (the studio, its parent, and children) func (q *Queries) GetStudiosByPerformerAndNetwork(ctx context.Context, arg GetStudiosByPerformerAndNetworkParams) ([]GetStudiosByPerformerAndNetworkRow, error) { rows, err := q.db.Query(ctx, getStudiosByPerformerAndNetwork, arg.PerformerID, arg.StudioID) if err != nil { return nil, err } defer rows.Close() items := []GetStudiosByPerformerAndNetworkRow{} for rows.Next() { var i GetStudiosByPerformerAndNetworkRow if err := rows.Scan( &i.Studio.ID, &i.Studio.Name, &i.Studio.ParentStudioID, &i.Studio.CreatedAt, &i.Studio.UpdatedAt, &i.Studio.Deleted, &i.SceneCount, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const reassignStudioFavorites = `-- name: ReassignStudioFavorites :exec UPDATE studio_favorites SET studio_id = $1 WHERE studio_favorites.studio_id = $2 AND user_id NOT IN ( SELECT user_id FROM studio_favorites SF WHERE SF.studio_id = $1 ) ` type ReassignStudioFavoritesParams struct { NewStudioID uuid.UUID `db:"new_studio_id" json:"new_studio_id"` OldStudioID uuid.UUID `db:"old_studio_id" json:"old_studio_id"` } func (q *Queries) ReassignStudioFavorites(ctx context.Context, arg ReassignStudioFavoritesParams) error { _, err := q.db.Exec(ctx, reassignStudioFavorites, arg.NewStudioID, arg.OldStudioID) return err } const searchStudios = `-- name: SearchStudios :many SELECT studio_id, pdb.agg('{"value_count": {"field": "studio_id"}}') OVER () as total_count FROM studio_search WHERE studio_id @@@ paradedb.boolean( should => ARRAY[ paradedb.boost(factor => 2, query => paradedb.match(field => 'name', value => $1::TEXT)), paradedb.match(field => 'network', value => $1::TEXT), paradedb.match(field => 'aliases', value => $1::TEXT) ] ) ORDER BY pdb.score(studio_id) DESC LIMIT $2 ` type SearchStudiosParams struct { Term *string `db:"term" json:"term"` Limit int32 `db:"limit" json:"limit"` } type SearchStudiosRow struct { StudioID uuid.UUID `db:"studio_id" json:"studio_id"` TotalCount interface{} `db:"total_count" json:"total_count"` } func (q *Queries) SearchStudios(ctx context.Context, arg SearchStudiosParams) ([]SearchStudiosRow, error) { rows, err := q.db.Query(ctx, searchStudios, arg.Term, arg.Limit) if err != nil { return nil, err } defer rows.Close() items := []SearchStudiosRow{} for rows.Next() { var i SearchStudiosRow if err := rows.Scan(&i.StudioID, &i.TotalCount); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const softDeleteStudio = `-- name: SoftDeleteStudio :one UPDATE studios SET deleted = true, updated_at = NOW() WHERE id = $1 RETURNING id, name, parent_studio_id, created_at, updated_at, deleted ` func (q *Queries) SoftDeleteStudio(ctx context.Context, id uuid.UUID) (Studio, error) { row := q.db.QueryRow(ctx, softDeleteStudio, id) var i Studio err := row.Scan( &i.ID, &i.Name, &i.ParentStudioID, &i.CreatedAt, &i.UpdatedAt, &i.Deleted, ) return i, err } const updateStudio = `-- name: UpdateStudio :one UPDATE studios SET name = $2, parent_studio_id = $3, updated_at = NOW() WHERE id = $1 RETURNING id, name, parent_studio_id, created_at, updated_at, deleted ` type UpdateStudioParams struct { ID uuid.UUID `db:"id" json:"id"` Name string `db:"name" json:"name"` ParentStudioID uuid.NullUUID `db:"parent_studio_id" json:"parent_studio_id"` } func (q *Queries) UpdateStudio(ctx context.Context, arg UpdateStudioParams) (Studio, error) { row := q.db.QueryRow(ctx, updateStudio, arg.ID, arg.Name, arg.ParentStudioID) var i Studio err := row.Scan( &i.ID, &i.Name, &i.ParentStudioID, &i.CreatedAt, &i.UpdatedAt, &i.Deleted, ) return i, err } const updateStudioRedirects = `-- name: UpdateStudioRedirects :exec UPDATE studio_redirects SET target_id = $1 WHERE target_id = $2 ` type UpdateStudioRedirectsParams struct { NewTargetID uuid.UUID `db:"new_target_id" json:"new_target_id"` OldTargetID uuid.UUID `db:"old_target_id" json:"old_target_id"` } func (q *Queries) UpdateStudioRedirects(ctx context.Context, arg UpdateStudioRedirectsParams) error { _, err := q.db.Exec(ctx, updateStudioRedirects, arg.NewTargetID, arg.OldTargetID) return err } ================================================ FILE: internal/queries/tag.sql.go ================================================ // Code generated by sqlc. DO NOT EDIT. // versions: // sqlc v1.29.0 // source: tag.sql package queries import ( "context" "github.com/gofrs/uuid" ) type CreateSceneTagsParams struct { SceneID uuid.UUID `db:"scene_id" json:"scene_id"` TagID uuid.UUID `db:"tag_id" json:"tag_id"` } const createTag = `-- name: CreateTag :one INSERT INTO tags (id, name, category_id, description, created_at, updated_at) VALUES ($1, $2, $3, $4, now(), now()) RETURNING id, name, description, created_at, updated_at, deleted, category_id ` type CreateTagParams struct { ID uuid.UUID `db:"id" json:"id"` Name string `db:"name" json:"name"` CategoryID uuid.NullUUID `db:"category_id" json:"category_id"` Description *string `db:"description" json:"description"` } // Tag queries func (q *Queries) CreateTag(ctx context.Context, arg CreateTagParams) (Tag, error) { row := q.db.QueryRow(ctx, createTag, arg.ID, arg.Name, arg.CategoryID, arg.Description, ) var i Tag err := row.Scan( &i.ID, &i.Name, &i.Description, &i.CreatedAt, &i.UpdatedAt, &i.Deleted, &i.CategoryID, ) return i, err } type CreateTagAliasesParams struct { TagID uuid.UUID `db:"tag_id" json:"tag_id"` Alias string `db:"alias" json:"alias"` } const createTagRedirect = `-- name: CreateTagRedirect :exec INSERT INTO tag_redirects (source_id, target_id) VALUES ($1, $2) ` type CreateTagRedirectParams struct { SourceID uuid.UUID `db:"source_id" json:"source_id"` TargetID uuid.UUID `db:"target_id" json:"target_id"` } // Tag redirects func (q *Queries) CreateTagRedirect(ctx context.Context, arg CreateTagRedirectParams) error { _, err := q.db.Exec(ctx, createTagRedirect, arg.SourceID, arg.TargetID) return err } const deleteSceneTagsByScene = `-- name: DeleteSceneTagsByScene :exec DELETE FROM scene_tags WHERE scene_id = $1 ` func (q *Queries) DeleteSceneTagsByScene(ctx context.Context, sceneID uuid.UUID) error { _, err := q.db.Exec(ctx, deleteSceneTagsByScene, sceneID) return err } const deleteSceneTagsByTag = `-- name: DeleteSceneTagsByTag :exec DELETE FROM scene_tags WHERE tag_id = $1 ` func (q *Queries) DeleteSceneTagsByTag(ctx context.Context, tagID uuid.UUID) error { _, err := q.db.Exec(ctx, deleteSceneTagsByTag, tagID) return err } const deleteTag = `-- name: DeleteTag :exec DELETE FROM tags WHERE id = $1 ` func (q *Queries) DeleteTag(ctx context.Context, id uuid.UUID) error { _, err := q.db.Exec(ctx, deleteTag, id) return err } const deleteTagAliases = `-- name: DeleteTagAliases :exec DELETE FROM tag_aliases WHERE tag_id = $1 ` func (q *Queries) DeleteTagAliases(ctx context.Context, tagID uuid.UUID) error { _, err := q.db.Exec(ctx, deleteTagAliases, tagID) return err } const deleteTagAliasesByNames = `-- name: DeleteTagAliasesByNames :exec DELETE FROM tag_aliases WHERE tag_id = $1 AND alias = ANY($2::TEXT[]) ` type DeleteTagAliasesByNamesParams struct { TagID uuid.UUID `db:"tag_id" json:"tag_id"` Column2 []string `db:"column_2" json:"column_2"` } func (q *Queries) DeleteTagAliasesByNames(ctx context.Context, arg DeleteTagAliasesByNamesParams) error { _, err := q.db.Exec(ctx, deleteTagAliasesByNames, arg.TagID, arg.Column2) return err } const findTag = `-- name: FindTag :one SELECT id, name, description, created_at, updated_at, deleted, category_id FROM tags WHERE id = $1 ` func (q *Queries) FindTag(ctx context.Context, id uuid.UUID) (Tag, error) { row := q.db.QueryRow(ctx, findTag, id) var i Tag err := row.Scan( &i.ID, &i.Name, &i.Description, &i.CreatedAt, &i.UpdatedAt, &i.Deleted, &i.CategoryID, ) return i, err } const findTagByAlias = `-- name: FindTagByAlias :one SELECT t.id, t.name, t.description, t.created_at, t.updated_at, t.deleted, t.category_id FROM tags t JOIN tag_aliases ta ON t.id = ta.tag_id WHERE UPPER(ta.alias) = UPPER($1) AND t.deleted = false ` func (q *Queries) FindTagByAlias(ctx context.Context, upper interface{}) (Tag, error) { row := q.db.QueryRow(ctx, findTagByAlias, upper) var i Tag err := row.Scan( &i.ID, &i.Name, &i.Description, &i.CreatedAt, &i.UpdatedAt, &i.Deleted, &i.CategoryID, ) return i, err } const findTagByName = `-- name: FindTagByName :one SELECT id, name, description, created_at, updated_at, deleted, category_id FROM tags WHERE UPPER(name) = UPPER($1) AND deleted = false ` func (q *Queries) FindTagByName(ctx context.Context, upper interface{}) (Tag, error) { row := q.db.QueryRow(ctx, findTagByName, upper) var i Tag err := row.Scan( &i.ID, &i.Name, &i.Description, &i.CreatedAt, &i.UpdatedAt, &i.Deleted, &i.CategoryID, ) return i, err } const findTagByNameOrAlias = `-- name: FindTagByNameOrAlias :one SELECT t.id, t.name, t.description, t.created_at, t.updated_at, t.deleted, t.category_id FROM tags T LEFT JOIN tag_aliases TA ON T.id = TA.tag_id WHERE ( LOWER(TA.alias) = LOWER($1) OR LOWER(T.name) = LOWER($1) ) AND T.deleted = FALSE ` func (q *Queries) FindTagByNameOrAlias(ctx context.Context, lower string) (Tag, error) { row := q.db.QueryRow(ctx, findTagByNameOrAlias, lower) var i Tag err := row.Scan( &i.ID, &i.Name, &i.Description, &i.CreatedAt, &i.UpdatedAt, &i.Deleted, &i.CategoryID, ) return i, err } const findTagIdsBySceneIds = `-- name: FindTagIdsBySceneIds :many SELECT scene_id, tag_id FROM scene_tags WHERE scene_id = ANY($1::UUID[]) ` // Bulk query to find tag IDs for multiple scene IDs func (q *Queries) FindTagIdsBySceneIds(ctx context.Context, sceneIds []uuid.UUID) ([]SceneTag, error) { rows, err := q.db.Query(ctx, findTagIdsBySceneIds, sceneIds) if err != nil { return nil, err } defer rows.Close() items := []SceneTag{} for rows.Next() { var i SceneTag if err := rows.Scan(&i.SceneID, &i.TagID); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const findTagWithRedirect = `-- name: FindTagWithRedirect :many SELECT t.id, t.name, t.description, t.created_at, t.updated_at, t.deleted, t.category_id FROM tags T WHERE T.id = $1 AND T.deleted = FALSE UNION SELECT tt.id, tt.name, tt.description, tt.created_at, tt.updated_at, tt.deleted, tt.category_id FROM tag_redirects R JOIN tags TT ON TT.id = R.target_id WHERE R.source_id = $1 AND TT.deleted = FALSE ` func (q *Queries) FindTagWithRedirect(ctx context.Context, id uuid.UUID) ([]Tag, error) { rows, err := q.db.Query(ctx, findTagWithRedirect, id) if err != nil { return nil, err } defer rows.Close() items := []Tag{} for rows.Next() { var i Tag if err := rows.Scan( &i.ID, &i.Name, &i.Description, &i.CreatedAt, &i.UpdatedAt, &i.Deleted, &i.CategoryID, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const findTagsByIds = `-- name: FindTagsByIds :many SELECT id, name, description, created_at, updated_at, deleted, category_id FROM tags WHERE id = ANY($1::UUID[]) ` func (q *Queries) FindTagsByIds(ctx context.Context, dollar_1 []uuid.UUID) ([]Tag, error) { rows, err := q.db.Query(ctx, findTagsByIds, dollar_1) if err != nil { return nil, err } defer rows.Close() items := []Tag{} for rows.Next() { var i Tag if err := rows.Scan( &i.ID, &i.Name, &i.Description, &i.CreatedAt, &i.UpdatedAt, &i.Deleted, &i.CategoryID, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const findTagsBySceneID = `-- name: FindTagsBySceneID :many SELECT t.id, t.name, t.description, t.created_at, t.updated_at, t.deleted, t.category_id FROM tags t INNER JOIN scene_tags st ON st.tag_id = t.id WHERE st.scene_id = $1 ` func (q *Queries) FindTagsBySceneID(ctx context.Context, sceneID uuid.UUID) ([]Tag, error) { rows, err := q.db.Query(ctx, findTagsBySceneID, sceneID) if err != nil { return nil, err } defer rows.Close() items := []Tag{} for rows.Next() { var i Tag if err := rows.Scan( &i.ID, &i.Name, &i.Description, &i.CreatedAt, &i.UpdatedAt, &i.Deleted, &i.CategoryID, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getSceneTags = `-- name: GetSceneTags :many SELECT t.id, t.name, t.description, t.created_at, t.updated_at, t.deleted, t.category_id FROM scene_tags ST JOIN tags T ON ST.tag_id = T.id WHERE scene_id = $1 ` func (q *Queries) GetSceneTags(ctx context.Context, sceneID uuid.UUID) ([]Tag, error) { rows, err := q.db.Query(ctx, getSceneTags, sceneID) if err != nil { return nil, err } defer rows.Close() items := []Tag{} for rows.Next() { var i Tag if err := rows.Scan( &i.ID, &i.Name, &i.Description, &i.CreatedAt, &i.UpdatedAt, &i.Deleted, &i.CategoryID, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getTagAliases = `-- name: GetTagAliases :many SELECT alias FROM tag_aliases WHERE tag_id = $1 ` func (q *Queries) GetTagAliases(ctx context.Context, tagID uuid.UUID) ([]string, error) { rows, err := q.db.Query(ctx, getTagAliases, tagID) if err != nil { return nil, err } defer rows.Close() items := []string{} for rows.Next() { var alias string if err := rows.Scan(&alias); err != nil { return nil, err } items = append(items, alias) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const searchTags = `-- name: SearchTags :many SELECT t.id, t.name, t.description, t.created_at, t.updated_at, t.deleted, t.category_id FROM tags T JOIN tag_search TS ON TS.tag_id = T.id WHERE TS.tag_id @@@ paradedb.boolean(should => ARRAY[ paradedb.fuzzy_term(field => 'name', value => $1::TEXT, distance => 1, prefix => true), paradedb.fuzzy_term(field => 'aliases', value => $1::TEXT, distance => 1, prefix => true) ]) AND T.deleted = FALSE ORDER BY paradedb.score(TS.tag_id) DESC LIMIT $2 ` type SearchTagsParams struct { Term *string `db:"term" json:"term"` Limit int32 `db:"limit" json:"limit"` } func (q *Queries) SearchTags(ctx context.Context, arg SearchTagsParams) ([]Tag, error) { rows, err := q.db.Query(ctx, searchTags, arg.Term, arg.Limit) if err != nil { return nil, err } defer rows.Close() items := []Tag{} for rows.Next() { var i Tag if err := rows.Scan( &i.ID, &i.Name, &i.Description, &i.CreatedAt, &i.UpdatedAt, &i.Deleted, &i.CategoryID, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const softDeleteTag = `-- name: SoftDeleteTag :one UPDATE tags SET deleted = true, updated_at = NOW() WHERE id = $1 RETURNING id, name, description, created_at, updated_at, deleted, category_id ` func (q *Queries) SoftDeleteTag(ctx context.Context, id uuid.UUID) (Tag, error) { row := q.db.QueryRow(ctx, softDeleteTag, id) var i Tag err := row.Scan( &i.ID, &i.Name, &i.Description, &i.CreatedAt, &i.UpdatedAt, &i.Deleted, &i.CategoryID, ) return i, err } const updateSceneTagsForMerge = `-- name: UpdateSceneTagsForMerge :exec UPDATE scene_tags SET tag_id = $1 WHERE scene_tags.tag_id = $2 AND scene_id NOT IN (SELECT scene_id from scene_tags st WHERE st.tag_id = $1) ` type UpdateSceneTagsForMergeParams struct { NewTagID uuid.UUID `db:"new_tag_id" json:"new_tag_id"` OldTagID uuid.UUID `db:"old_tag_id" json:"old_tag_id"` } func (q *Queries) UpdateSceneTagsForMerge(ctx context.Context, arg UpdateSceneTagsForMergeParams) error { _, err := q.db.Exec(ctx, updateSceneTagsForMerge, arg.NewTagID, arg.OldTagID) return err } const updateTag = `-- name: UpdateTag :one UPDATE tags SET name = $2, category_id = $3, description = $4, updated_at = NOW() WHERE id = $1 RETURNING id, name, description, created_at, updated_at, deleted, category_id ` type UpdateTagParams struct { ID uuid.UUID `db:"id" json:"id"` Name string `db:"name" json:"name"` CategoryID uuid.NullUUID `db:"category_id" json:"category_id"` Description *string `db:"description" json:"description"` } func (q *Queries) UpdateTag(ctx context.Context, arg UpdateTagParams) (Tag, error) { row := q.db.QueryRow(ctx, updateTag, arg.ID, arg.Name, arg.CategoryID, arg.Description, ) var i Tag err := row.Scan( &i.ID, &i.Name, &i.Description, &i.CreatedAt, &i.UpdatedAt, &i.Deleted, &i.CategoryID, ) return i, err } const updateTagRedirects = `-- name: UpdateTagRedirects :exec UPDATE tag_redirects SET target_id = $1 WHERE target_id = $2 ` type UpdateTagRedirectsParams struct { NewTargetID uuid.UUID `db:"new_target_id" json:"new_target_id"` OldTargetID uuid.UUID `db:"old_target_id" json:"old_target_id"` } func (q *Queries) UpdateTagRedirects(ctx context.Context, arg UpdateTagRedirectsParams) error { _, err := q.db.Exec(ctx, updateTagRedirects, arg.NewTargetID, arg.OldTargetID) return err } ================================================ FILE: internal/queries/tag_category.sql.go ================================================ // Code generated by sqlc. DO NOT EDIT. // versions: // sqlc v1.29.0 // source: tag_category.sql package queries import ( "context" "github.com/gofrs/uuid" ) const createTagCategory = `-- name: CreateTagCategory :one INSERT INTO tag_categories (id, "group", name, description, created_at, updated_at) VALUES ($1, $2, $3, $4, now(), now()) RETURNING id, "group", name, description, created_at, updated_at ` type CreateTagCategoryParams struct { ID uuid.UUID `db:"id" json:"id"` Group string `db:"group" json:"group"` Name string `db:"name" json:"name"` Description *string `db:"description" json:"description"` } // Tag category queries func (q *Queries) CreateTagCategory(ctx context.Context, arg CreateTagCategoryParams) (TagCategory, error) { row := q.db.QueryRow(ctx, createTagCategory, arg.ID, arg.Group, arg.Name, arg.Description, ) var i TagCategory err := row.Scan( &i.ID, &i.Group, &i.Name, &i.Description, &i.CreatedAt, &i.UpdatedAt, ) return i, err } const deleteTagCategory = `-- name: DeleteTagCategory :exec DELETE FROM tag_categories WHERE id = $1 ` func (q *Queries) DeleteTagCategory(ctx context.Context, id uuid.UUID) error { _, err := q.db.Exec(ctx, deleteTagCategory, id) return err } const findTagCategory = `-- name: FindTagCategory :one SELECT id, "group", name, description, created_at, updated_at FROM tag_categories WHERE id = $1 ` func (q *Queries) FindTagCategory(ctx context.Context, id uuid.UUID) (TagCategory, error) { row := q.db.QueryRow(ctx, findTagCategory, id) var i TagCategory err := row.Scan( &i.ID, &i.Group, &i.Name, &i.Description, &i.CreatedAt, &i.UpdatedAt, ) return i, err } const getAllTagCategories = `-- name: GetAllTagCategories :many SELECT id, "group", name, description, created_at, updated_at FROM tag_categories ORDER BY name ASC ` func (q *Queries) GetAllTagCategories(ctx context.Context) ([]TagCategory, error) { rows, err := q.db.Query(ctx, getAllTagCategories) if err != nil { return nil, err } defer rows.Close() items := []TagCategory{} for rows.Next() { var i TagCategory if err := rows.Scan( &i.ID, &i.Group, &i.Name, &i.Description, &i.CreatedAt, &i.UpdatedAt, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getTagCategoriesByIds = `-- name: GetTagCategoriesByIds :many SELECT id, "group", name, description, created_at, updated_at FROM tag_categories WHERE id = ANY($1::UUID[]) ` func (q *Queries) GetTagCategoriesByIds(ctx context.Context, dollar_1 []uuid.UUID) ([]TagCategory, error) { rows, err := q.db.Query(ctx, getTagCategoriesByIds, dollar_1) if err != nil { return nil, err } defer rows.Close() items := []TagCategory{} for rows.Next() { var i TagCategory if err := rows.Scan( &i.ID, &i.Group, &i.Name, &i.Description, &i.CreatedAt, &i.UpdatedAt, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const updateTagCategory = `-- name: UpdateTagCategory :one UPDATE tag_categories SET "group" = $2, name = $3, description = $4, updated_at = now() WHERE id = $1 RETURNING id, "group", name, description, created_at, updated_at ` type UpdateTagCategoryParams struct { ID uuid.UUID `db:"id" json:"id"` Group string `db:"group" json:"group"` Name string `db:"name" json:"name"` Description *string `db:"description" json:"description"` } func (q *Queries) UpdateTagCategory(ctx context.Context, arg UpdateTagCategoryParams) (TagCategory, error) { row := q.db.QueryRow(ctx, updateTagCategory, arg.ID, arg.Group, arg.Name, arg.Description, ) var i TagCategory err := row.Scan( &i.ID, &i.Group, &i.Name, &i.Description, &i.CreatedAt, &i.UpdatedAt, ) return i, err } ================================================ FILE: internal/queries/types.go ================================================ package queries // WithTxnFunc is a function type for handling transactions // The function receives a *Queries object initialized with the transaction type WithTxnFunc func(func(*Queries) error) error // Service interface that all services should implement type Service interface { WithTxn(func(*Queries) error) error } ================================================ FILE: internal/queries/user.sql.go ================================================ // Code generated by sqlc. DO NOT EDIT. // versions: // sqlc v1.29.0 // source: user.sql package queries import ( "context" "github.com/gofrs/uuid" ) const countUserEditsByStatus = `-- name: CountUserEditsByStatus :many SELECT status, COUNT(*) as count FROM edits WHERE user_id = $1 GROUP BY status ` type CountUserEditsByStatusRow struct { Status string `db:"status" json:"status"` Count int64 `db:"count" json:"count"` } func (q *Queries) CountUserEditsByStatus(ctx context.Context, userID uuid.NullUUID) ([]CountUserEditsByStatusRow, error) { rows, err := q.db.Query(ctx, countUserEditsByStatus, userID) if err != nil { return nil, err } defer rows.Close() items := []CountUserEditsByStatusRow{} for rows.Next() { var i CountUserEditsByStatusRow if err := rows.Scan(&i.Status, &i.Count); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const countUsers = `-- name: CountUsers :one SELECT COUNT(*) FROM users ` func (q *Queries) CountUsers(ctx context.Context) (int64, error) { row := q.db.QueryRow(ctx, countUsers) var count int64 err := row.Scan(&count) return count, err } const countVotesByType = `-- name: CountVotesByType :many SELECT vote, COUNT(*) as count FROM edit_votes WHERE user_id = $1 GROUP BY vote ` type CountVotesByTypeRow struct { Vote string `db:"vote" json:"vote"` Count int64 `db:"count" json:"count"` } func (q *Queries) CountVotesByType(ctx context.Context, userID uuid.UUID) ([]CountVotesByTypeRow, error) { rows, err := q.db.Query(ctx, countVotesByType, userID) if err != nil { return nil, err } defer rows.Close() items := []CountVotesByTypeRow{} for rows.Next() { var i CountVotesByTypeRow if err := rows.Scan(&i.Vote, &i.Count); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const createUser = `-- name: CreateUser :one INSERT INTO users (id, name, password_hash, email, api_key, api_calls, invite_tokens, invited_by, last_api_call, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, NOW(), NOW(), NOW()) RETURNING id, name, password_hash, email, api_key, api_calls, last_api_call, created_at, updated_at, invited_by, invite_tokens ` type CreateUserParams struct { ID uuid.UUID `db:"id" json:"id"` Name string `db:"name" json:"name"` PasswordHash string `db:"password_hash" json:"password_hash"` Email string `db:"email" json:"email"` ApiKey string `db:"api_key" json:"api_key"` ApiCalls *int `db:"api_calls" json:"api_calls"` InviteTokens int `db:"invite_tokens" json:"invite_tokens"` InvitedBy uuid.NullUUID `db:"invited_by" json:"invited_by"` } // User queries func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (User, error) { row := q.db.QueryRow(ctx, createUser, arg.ID, arg.Name, arg.PasswordHash, arg.Email, arg.ApiKey, arg.ApiCalls, arg.InviteTokens, arg.InvitedBy, ) var i User err := row.Scan( &i.ID, &i.Name, &i.PasswordHash, &i.Email, &i.ApiKey, &i.ApiCalls, &i.LastApiCall, &i.CreatedAt, &i.UpdatedAt, &i.InvitedBy, &i.InviteTokens, ) return i, err } type CreateUserRolesParams struct { UserID uuid.UUID `db:"user_id" json:"user_id"` Role string `db:"role" json:"role"` } const deleteUser = `-- name: DeleteUser :exec DELETE FROM users WHERE id = $1 ` func (q *Queries) DeleteUser(ctx context.Context, id uuid.UUID) error { _, err := q.db.Exec(ctx, deleteUser, id) return err } const deleteUserRoles = `-- name: DeleteUserRoles :exec DELETE FROM user_roles WHERE user_id = $1 ` func (q *Queries) DeleteUserRoles(ctx context.Context, userID uuid.UUID) error { _, err := q.db.Exec(ctx, deleteUserRoles, userID) return err } const findUser = `-- name: FindUser :one SELECT id, name, password_hash, email, api_key, api_calls, last_api_call, created_at, updated_at, invited_by, invite_tokens FROM users WHERE id = $1 ` func (q *Queries) FindUser(ctx context.Context, id uuid.UUID) (User, error) { row := q.db.QueryRow(ctx, findUser, id) var i User err := row.Scan( &i.ID, &i.Name, &i.PasswordHash, &i.Email, &i.ApiKey, &i.ApiCalls, &i.LastApiCall, &i.CreatedAt, &i.UpdatedAt, &i.InvitedBy, &i.InviteTokens, ) return i, err } const findUserByEmail = `-- name: FindUserByEmail :one SELECT id, name, password_hash, email, api_key, api_calls, last_api_call, created_at, updated_at, invited_by, invite_tokens FROM users WHERE UPPER(email) = UPPER($1) ` func (q *Queries) FindUserByEmail(ctx context.Context, upper interface{}) (User, error) { row := q.db.QueryRow(ctx, findUserByEmail, upper) var i User err := row.Scan( &i.ID, &i.Name, &i.PasswordHash, &i.Email, &i.ApiKey, &i.ApiCalls, &i.LastApiCall, &i.CreatedAt, &i.UpdatedAt, &i.InvitedBy, &i.InviteTokens, ) return i, err } const findUserByName = `-- name: FindUserByName :one SELECT id, name, password_hash, email, api_key, api_calls, last_api_call, created_at, updated_at, invited_by, invite_tokens FROM users WHERE UPPER(name) = UPPER($1::text) ` func (q *Queries) FindUserByName(ctx context.Context, name string) (User, error) { row := q.db.QueryRow(ctx, findUserByName, name) var i User err := row.Scan( &i.ID, &i.Name, &i.PasswordHash, &i.Email, &i.ApiKey, &i.ApiCalls, &i.LastApiCall, &i.CreatedAt, &i.UpdatedAt, &i.InvitedBy, &i.InviteTokens, ) return i, err } const getUserNotificationSubscriptions = `-- name: GetUserNotificationSubscriptions :many SELECT type FROM user_notifications WHERE user_id = $1 ` func (q *Queries) GetUserNotificationSubscriptions(ctx context.Context, userID uuid.UUID) ([]NotificationType, error) { rows, err := q.db.Query(ctx, getUserNotificationSubscriptions, userID) if err != nil { return nil, err } defer rows.Close() items := []NotificationType{} for rows.Next() { var type_ NotificationType if err := rows.Scan(&type_); err != nil { return nil, err } items = append(items, type_) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getUserRoles = `-- name: GetUserRoles :many SELECT role FROM user_roles WHERE user_id = $1 ` func (q *Queries) GetUserRoles(ctx context.Context, userID uuid.UUID) ([]string, error) { rows, err := q.db.Query(ctx, getUserRoles, userID) if err != nil { return nil, err } defer rows.Close() items := []string{} for rows.Next() { var role string if err := rows.Scan(&role); err != nil { return nil, err } items = append(items, role) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const updateUser = `-- name: UpdateUser :one UPDATE users SET name = $2, password_hash = $3, email = $4, updated_at = NOW() WHERE id = $1 RETURNING id, name, password_hash, email, api_key, api_calls, last_api_call, created_at, updated_at, invited_by, invite_tokens ` type UpdateUserParams struct { ID uuid.UUID `db:"id" json:"id"` Name string `db:"name" json:"name"` PasswordHash string `db:"password_hash" json:"password_hash"` Email string `db:"email" json:"email"` } func (q *Queries) UpdateUser(ctx context.Context, arg UpdateUserParams) (User, error) { row := q.db.QueryRow(ctx, updateUser, arg.ID, arg.Name, arg.PasswordHash, arg.Email, ) var i User err := row.Scan( &i.ID, &i.Name, &i.PasswordHash, &i.Email, &i.ApiKey, &i.ApiCalls, &i.LastApiCall, &i.CreatedAt, &i.UpdatedAt, &i.InvitedBy, &i.InviteTokens, ) return i, err } const updateUserAPIKey = `-- name: UpdateUserAPIKey :exec UPDATE users SET api_key = $2, updated_at = NOW() WHERE id = $1 ` type UpdateUserAPIKeyParams struct { ID uuid.UUID `db:"id" json:"id"` ApiKey string `db:"api_key" json:"api_key"` } func (q *Queries) UpdateUserAPIKey(ctx context.Context, arg UpdateUserAPIKeyParams) error { _, err := q.db.Exec(ctx, updateUserAPIKey, arg.ID, arg.ApiKey) return err } const updateUserEmail = `-- name: UpdateUserEmail :exec UPDATE users SET email = $2, updated_at = NOW() WHERE id = $1 ` type UpdateUserEmailParams struct { ID uuid.UUID `db:"id" json:"id"` Email string `db:"email" json:"email"` } func (q *Queries) UpdateUserEmail(ctx context.Context, arg UpdateUserEmailParams) error { _, err := q.db.Exec(ctx, updateUserEmail, arg.ID, arg.Email) return err } const updateUserInviteTokenCount = `-- name: UpdateUserInviteTokenCount :exec UPDATE users SET invite_tokens = $2 WHERE id = $1 ` type UpdateUserInviteTokenCountParams struct { ID uuid.UUID `db:"id" json:"id"` InviteTokens int `db:"invite_tokens" json:"invite_tokens"` } func (q *Queries) UpdateUserInviteTokenCount(ctx context.Context, arg UpdateUserInviteTokenCountParams) error { _, err := q.db.Exec(ctx, updateUserInviteTokenCount, arg.ID, arg.InviteTokens) return err } const updateUserPassword = `-- name: UpdateUserPassword :exec UPDATE users SET password_hash = $2, updated_at = NOW() WHERE id = $1 ` type UpdateUserPasswordParams struct { ID uuid.UUID `db:"id" json:"id"` PasswordHash string `db:"password_hash" json:"password_hash"` } func (q *Queries) UpdateUserPassword(ctx context.Context, arg UpdateUserPasswordParams) error { _, err := q.db.Exec(ctx, updateUserPassword, arg.ID, arg.PasswordHash) return err } ================================================ FILE: internal/queries/user_token.sql.go ================================================ // Code generated by sqlc. DO NOT EDIT. // versions: // sqlc v1.29.0 // source: user_token.sql package queries import ( "context" "time" "github.com/gofrs/uuid" ) const createUserToken = `-- name: CreateUserToken :one INSERT INTO user_tokens (id, data, type, created_at, expires_at) VALUES ($1, $2, $3, $4, $5) RETURNING id, data, type, created_at, expires_at ` type CreateUserTokenParams struct { ID uuid.UUID `db:"id" json:"id"` Data []byte `db:"data" json:"data"` Type string `db:"type" json:"type"` CreatedAt time.Time `db:"created_at" json:"created_at"` ExpiresAt time.Time `db:"expires_at" json:"expires_at"` } // User token queries func (q *Queries) CreateUserToken(ctx context.Context, arg CreateUserTokenParams) (UserToken, error) { row := q.db.QueryRow(ctx, createUserToken, arg.ID, arg.Data, arg.Type, arg.CreatedAt, arg.ExpiresAt, ) var i UserToken err := row.Scan( &i.ID, &i.Data, &i.Type, &i.CreatedAt, &i.ExpiresAt, ) return i, err } const deleteExpiredUserTokens = `-- name: DeleteExpiredUserTokens :exec DELETE FROM user_tokens WHERE expires_at <= now() ` func (q *Queries) DeleteExpiredUserTokens(ctx context.Context) error { _, err := q.db.Exec(ctx, deleteExpiredUserTokens) return err } const deleteUserToken = `-- name: DeleteUserToken :exec DELETE FROM user_tokens WHERE id = $1 ` func (q *Queries) DeleteUserToken(ctx context.Context, id uuid.UUID) error { _, err := q.db.Exec(ctx, deleteUserToken, id) return err } const findUserToken = `-- name: FindUserToken :one SELECT id, data, type, created_at, expires_at FROM user_tokens WHERE id = $1 ` func (q *Queries) FindUserToken(ctx context.Context, id uuid.UUID) (UserToken, error) { row := q.db.QueryRow(ctx, findUserToken, id) var i UserToken err := row.Scan( &i.ID, &i.Data, &i.Type, &i.CreatedAt, &i.ExpiresAt, ) return i, err } const findUserTokensByEmail = `-- name: FindUserTokensByEmail :many SELECT id, data, type, created_at, expires_at FROM user_tokens WHERE data->>'email' = $1::text ` func (q *Queries) FindUserTokensByEmail(ctx context.Context, dollar_1 string) ([]UserToken, error) { rows, err := q.db.Query(ctx, findUserTokensByEmail, dollar_1) if err != nil { return nil, err } defer rows.Close() items := []UserToken{} for rows.Next() { var i UserToken if err := rows.Scan( &i.ID, &i.Data, &i.Type, &i.CreatedAt, &i.ExpiresAt, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const findUserTokensByInviteKey = `-- name: FindUserTokensByInviteKey :many SELECT id, data, type, created_at, expires_at FROM user_tokens WHERE (data->>'invite_key')::UUID = $1::UUID ` func (q *Queries) FindUserTokensByInviteKey(ctx context.Context, dollar_1 uuid.UUID) ([]UserToken, error) { rows, err := q.db.Query(ctx, findUserTokensByInviteKey, dollar_1) if err != nil { return nil, err } defer rows.Close() items := []UserToken{} for rows.Next() { var i UserToken if err := rows.Scan( &i.ID, &i.Data, &i.Type, &i.CreatedAt, &i.ExpiresAt, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } ================================================ FILE: internal/service/draft/service.go ================================================ package draft import ( "context" "fmt" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/auth" "github.com/stashapp/stash-box/internal/config" "github.com/stashapp/stash-box/internal/converter" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/internal/queries" "github.com/stashapp/stash-box/pkg/utils" ) type Draft struct { queries *queries.Queries withTxn queries.WithTxnFunc } func NewDraft(queries *queries.Queries, withTxn queries.WithTxnFunc) *Draft { return &Draft{ queries: queries, withTxn: withTxn, } } // FindPerformers takes a slice of DraftEntity performers and returns SceneDraftPerformer models // by using FindPerformersWithRedirects to resolve existing performers or keep as DraftEntity func (s *Draft) FindPerformers(ctx context.Context, draftPerformers []models.DraftEntity) ([]models.SceneDraftPerformer, error) { var result []models.SceneDraftPerformer for _, p := range draftPerformers { if p.ID != nil { dbPerformers, err := s.queries.FindPerformerWithRedirect(ctx, *p.ID) if err != nil { return nil, err } if len(dbPerformers) > 0 { result = append(result, converter.PerformerToModel(dbPerformers[0])) continue } } result = append(result, p) } return result, nil } // FindTags takes a slice of DraftEntity tags and returns SceneDraftTag models // by using FindTagsWithRedirects to resolve existing tags or keep as DraftEntity func (s *Draft) FindTags(ctx context.Context, draftTags []models.DraftEntity) ([]models.SceneDraftTag, error) { var result []models.SceneDraftTag for _, t := range draftTags { if t.ID != nil { dbTags, err := s.queries.FindTagWithRedirect(ctx, *t.ID) if err != nil { return nil, err } if len(dbTags) > 0 { result = append(result, converter.TagToModel(dbTags[0])) continue } } result = append(result, t) } return result, nil } // FindStudio takes a DraftEntity studio and returns SceneDraftStudio model // by using FindStudioWithRedirect to resolve existing studio or keep as DraftEntity func (s *Draft) FindStudio(ctx context.Context, draftStudio *models.DraftEntity) (models.SceneDraftStudio, error) { if draftStudio == nil { return nil, nil } // If the draft studio has an ID, try to find the actual studio if draftStudio.ID != nil { studio, err := s.queries.FindStudioWithRedirect(ctx, *draftStudio.ID) if err != nil { return nil, err } // Return the converted studio convertedStudio := converter.StudioToModel(studio) return convertedStudio, nil } // If no ID, return the draft entity return *draftStudio, nil } func (s *Draft) SubmitScene(ctx context.Context, input models.SceneDraftInput, imageID *uuid.UUID) (*models.DraftSubmissionStatus, error) { UUID, err := uuid.NewV7() if err != nil { return nil, err } user := auth.GetCurrentUser(ctx) newDraft := queries.CreateDraftParams{ ID: UUID, UserID: user.ID, Type: models.TargetTypeEnumScene.String(), } data := converter.SceneDraftInputToSceneDraft(input) data.Image = imageID err = s.withTxn(func(tx *queries.Queries) error { if len(input.Tags) > 0 { tags, err := s.resolveTags(ctx, input.Tags) if err != nil { return err } data.Tags = tags } // Temporary code, while we deprecate the URL parameter. if input.URL != nil { data.URLs = []string{*input.URL} } json, err := utils.ToJSON(data) if err != nil { return err } newDraft.Data = json _, err = tx.CreateDraft(ctx, newDraft) return err }) status := models.DraftSubmissionStatus{} if err == nil { status.ID = &newDraft.ID } return &status, err } func (s *Draft) SubmitPerformer(ctx context.Context, input models.PerformerDraftInput, imageID *uuid.UUID) (*models.DraftSubmissionStatus, error) { UUID, err := uuid.NewV7() if err != nil { return nil, err } user := auth.GetCurrentUser(ctx) newDraft := queries.CreateDraftParams{ ID: UUID, UserID: user.ID, Type: models.TargetTypeEnumPerformer.String(), } data := models.PerformerDraft{ ID: input.ID, Name: input.Name, Disambiguation: input.Disambiguation, Aliases: input.Aliases, Gender: input.Gender, Birthdate: input.Birthdate, Deathdate: input.Deathdate, Urls: input.Urls, Ethnicity: input.Ethnicity, Country: input.Country, EyeColor: input.EyeColor, HairColor: input.HairColor, Height: input.Height, Measurements: input.Measurements, BreastType: input.BreastType, Tattoos: input.Tattoos, Piercings: input.Piercings, CareerStartYear: input.CareerStartYear, CareerEndYear: input.CareerEndYear, Image: imageID, } err = s.withTxn(func(tx *queries.Queries) error { json, err := utils.ToJSON(data) if err != nil { return err } newDraft.Data = json _, err = tx.CreateDraft(ctx, newDraft) return err }) status := models.DraftSubmissionStatus{} if err == nil { status.ID = &newDraft.ID } return &status, err } func (s *Draft) Destroy(ctx context.Context, user *models.User, id uuid.UUID) (bool, error) { draft, err := s.queries.FindDraft(ctx, id) if err != nil { return false, err } if user == nil || draft.UserID != user.ID { return false, fmt.Errorf("unauthorized") } err = s.queries.DeleteDraft(ctx, id) return err == nil, err } func (s *Draft) resolveTags(ctx context.Context, tags []models.DraftEntityInput) ([]models.DraftEntity, error) { var results []models.DraftEntity resultMap := make(map[string]bool) for _, tag := range tags { res := models.DraftEntity{} if tag.ID != nil { dbTag, err := s.queries.FindTag(ctx, *tag.ID) if err == nil && dbTag.ID == *tag.ID { res.Name = dbTag.Name res.ID = &dbTag.ID } } else { foundTag, err := s.queries.FindTagByNameOrAlias(ctx, tag.Name) if err == nil { res.Name = foundTag.Name res.ID = &foundTag.ID } } if res.Name == "" { res = models.DraftEntity{ Name: tag.Name, } } if _, exists := resultMap[res.Name]; !exists { resultMap[res.Name] = true results = append(results, res) } } return results, nil } func (s *Draft) FindByUser(ctx context.Context, userID uuid.UUID) ([]models.Draft, error) { dbDrafts, err := s.queries.FindDraftsByUser(ctx, userID) var drafts []models.Draft for _, draft := range dbDrafts { drafts = append(drafts, converter.DraftToModel(draft)) } return drafts, err } func (s *Draft) FindByID(ctx context.Context, draftID uuid.UUID) (*models.Draft, error) { draft, err := s.queries.FindDraft(ctx, draftID) if err != nil { return nil, err } return converter.DraftToModelPtr(draft), err } func (s *Draft) DeleteExpired(ctx context.Context) error { return s.withTxn(func(tx *queries.Queries) error { return tx.DeleteExpiredDrafts(ctx, config.GetDraftTimeLimit()) }) } ================================================ FILE: internal/service/edit/edit.go ================================================ package edit import ( "context" "errors" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/converter" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/internal/queries" "github.com/stashapp/stash-box/pkg/utils" ) var ErrNoChanges = errors.New("edit contains no changes") var ErrMergeIDMissing = errors.New("merge target ID is required") var ErrMergeTargetIsSource = errors.New("merge target cannot be used as source") var ErrNoMergeSources = errors.New("no merge sources found") // InputSpecifiedFunc is function that returns true if the qualified field name // was specified in the input. Used to distinguish between nil/empty fields and // unspecified fields type InputSpecifiedFunc func(qualifiedField string) bool type mutator struct { context context.Context edit *models.Edit queries *queries.Queries } func (m *mutator) operation() models.OperationEnum { var operation models.OperationEnum utils.ResolveEnumString(m.edit.Operation, &operation) return operation } func (m *mutator) CreateEdit() (*models.Edit, error) { created, err := m.queries.CreateEdit(m.context, converter.EditToCreateParams(*m.edit)) if err != nil { return nil, err } converted := converter.EditToModelPtr(created) m.edit = converted return converted, nil } func (m *mutator) UpdateEdit() (*models.Edit, error) { m.edit.UpdateCount++ updatedEdit, err := m.queries.UpdateEdit(m.context, converter.EditToUpdateParams(*m.edit)) if err != nil { return nil, err } if err := m.queries.ResetVotes(m.context, m.edit.ID); err != nil { return nil, err } return converter.EditToModelPtr(updatedEdit), nil } func (m *mutator) CreateComment(user *models.User, comment *string) error { if comment != nil && len(*comment) > 0 { commentID, _ := uuid.NewV7() comment := models.NewEditComment(commentID, user.ID, m.edit, *comment) _, err := m.queries.CreateEditComment(m.context, converter.EditCommentToCreateParams(*comment)) return err } return nil } type editApplyer interface { apply() error } func urlCompare(subject []models.URL, against []models.URL) (added []models.URL, missing []models.URL) { for _, s := range subject { newMod := true for _, a := range against { if s.URL == a.URL && s.SiteID == a.SiteID { newMod = false } } for _, a := range added { if s.URL == a.URL && s.SiteID == a.SiteID { newMod = false } } if newMod { added = append(added, s) } } for _, s := range against { removedMod := true for _, a := range subject { if s.URL == a.URL && s.SiteID == a.SiteID { removedMod = false } } for _, a := range missing { if s.URL == a.URL && s.SiteID == a.SiteID { removedMod = false } } if removedMod { missing = append(missing, s) } } return } ================================================ FILE: internal/service/edit/modbot.go ================================================ package edit import ( "context" "fmt" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/queries" ) const modUserName = "StashBot" var modUserID *uuid.UUID func getModBot(ctx context.Context, tx *queries.Queries) uuid.UUID { if modUserID == nil { modUser, err := tx.FindUserByName(ctx, modUserName) if err != nil { panic(fmt.Errorf("mod user not found: %w", err)) } modUserID = &modUser.ID } return *modUserID } ================================================ FILE: internal/service/edit/performer.go ================================================ package edit import ( "context" "fmt" "reflect" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/converter" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/internal/queries" "github.com/stashapp/stash-box/pkg/utils" ) type PerformerEditProcessor struct { mutator } func Performer(ctx context.Context, queries *queries.Queries, edit *models.Edit) *PerformerEditProcessor { return &PerformerEditProcessor{ mutator{ context: ctx, queries: queries, edit: edit, }, } } func (m *PerformerEditProcessor) Edit(input models.PerformerEditInput, inputArgs utils.ArgumentsQuery, update bool) error { if err := validatePerformerEditInput(m.context, m.queries, input, m.edit, update); err != nil { return err } var err error switch input.Edit.Operation { case models.OperationEnumModify: err = m.modifyEdit(input, inputArgs) case models.OperationEnumMerge: err = m.mergeEdit(input, inputArgs) case models.OperationEnumDestroy: err = m.destroyEdit(input) case models.OperationEnumCreate: err = m.createEdit(input, inputArgs) } return err } func (m *PerformerEditProcessor) modifyEdit(input models.PerformerEditInput, inputArgs utils.ArgumentsQuery) error { // get the existing performer performerID := *input.Edit.ID dbPerformer, err := m.queries.FindPerformer(m.context, performerID) if err != nil { return err } performer := converter.PerformerToModel(dbPerformer) var entity editEntity = performer if err := validateEditEntity(&entity, *input.Edit.ID, "performer"); err != nil { return err } // perform a diff against the input and the current object detailArgs := inputArgs.Field("details") performerEdit, err := input.Details.PerformerEditFromDiff(performer, detailArgs) if err != nil { return err } if err = m.diffRelationships(performerEdit, performerID, input, inputArgs); err != nil { return err } if input.Options != nil && input.Options.SetModifyAliases != nil { performerEdit.SetModifyAliases = *input.Options.SetModifyAliases } if reflect.DeepEqual(performerEdit.Old, performerEdit.New) { return ErrNoChanges } performerEdit.New.DraftID = input.Details.DraftID return m.edit.SetData(*performerEdit) } func (m *PerformerEditProcessor) mergeEdit(input models.PerformerEditInput, inputArgs utils.ArgumentsQuery) error { // get the existing performer if input.Edit.ID == nil { return ErrMergeIDMissing } performerID := *input.Edit.ID dbPerformer, err := m.queries.FindPerformer(m.context, performerID) if err != nil { return fmt.Errorf("performer with id %v not found: %w", *input.Edit.ID, err) } var mergeSources []uuid.UUID for _, sourceID := range input.Edit.MergeSourceIds { _, err := m.queries.FindPerformer(m.context, sourceID) if err != nil { return fmt.Errorf("performer with id %v not found: %w", sourceID, err) } if performerID == sourceID { return ErrMergeTargetIsSource } mergeSources = append(mergeSources, sourceID) } if len(mergeSources) < 1 { return ErrNoMergeSources } // perform a diff against the input and the current object performer := converter.PerformerToModel(dbPerformer) detailArgs := inputArgs.Field("details") performerEdit, err := input.Details.PerformerEditFromMerge(performer, mergeSources, detailArgs) if err != nil { return err } if err = m.diffRelationships(performerEdit, performerID, input, inputArgs); err != nil { return err } if input.Options != nil && input.Options.SetMergeAliases != nil { performerEdit.SetMergeAliases = *input.Options.SetMergeAliases } if input.Options != nil && input.Options.SetModifyAliases != nil { performerEdit.SetModifyAliases = *input.Options.SetModifyAliases } return m.edit.SetData(*performerEdit) } func (m *PerformerEditProcessor) createEdit(input models.PerformerEditInput, inputArgs utils.ArgumentsQuery) error { performerEdit, err := input.Details.PerformerEditFromCreate(inputArgs) if err != nil { return err } performerEdit.New.AddedAliases = input.Details.Aliases performerEdit.New.AddedTattoos = converter.BodyModInputToModel(input.Details.Tattoos) performerEdit.New.AddedPiercings = converter.BodyModInputToModel(input.Details.Piercings) performerEdit.New.AddedImages = input.Details.ImageIds performerEdit.New.AddedUrls = input.Details.Urls performerEdit.New.DraftID = input.Details.DraftID return m.edit.SetData(*performerEdit) } func (m *PerformerEditProcessor) destroyEdit(input models.PerformerEditInput) error { // get the existing performer performerID := *input.Edit.ID dbPerformer, err := m.queries.FindPerformer(m.context, performerID) if err != nil { return err } performer := converter.PerformerToModel(dbPerformer) var entity editEntity = performer return validateEditEntity(&entity, performerID, "performer") } func (m *PerformerEditProcessor) CreateJoin(input models.PerformerEditInput) error { if input.Edit.ID != nil { return m.queries.CreatePerformerEdit(m.context, queries.CreatePerformerEditParams{ EditID: m.edit.ID, PerformerID: *input.Edit.ID, }) } return nil } func (m *PerformerEditProcessor) apply() error { operation := m.operation() isCreate := operation == models.OperationEnumCreate var performer *models.Performer if !isCreate { performerID, err := m.queries.GetEditTargetID(m.context, m.edit.ID) if err != nil { return err } dbPerformer, err := m.queries.FindPerformer(m.context, performerID.ID) if err != nil { return fmt.Errorf("%w: performer, %s: %w", ErrEntityNotFound, performerID, err) } performer = converter.PerformerToModelPtr(dbPerformer) } return m.applyEdit(performer) } func (m *PerformerEditProcessor) applyEdit(performer *models.Performer) error { data, err := m.edit.GetPerformerData() if err != nil { return err } operation := m.operation() switch operation { case models.OperationEnumCreate: return m.applyCreate(data) case models.OperationEnumDestroy: return m.applyDestroy(performer) case models.OperationEnumModify: return m.applyModify(performer, data) case models.OperationEnumMerge: return m.applyMerge(performer, data) } return nil } func (m *PerformerEditProcessor) applyCreate(data *models.PerformerEditData) error { UUID := data.New.DraftID if UUID == nil { newUUID, err := uuid.NewV7() if err != nil { return err } UUID = &newUUID } newPerformer := &models.Performer{ ID: *UUID, } if err := m.ApplyEdit(newPerformer, true, data); err != nil { return err } return m.queries.CreatePerformerEdit(m.context, queries.CreatePerformerEditParams{ EditID: m.edit.ID, PerformerID: newPerformer.ID, }) } func (m *PerformerEditProcessor) applyModify(performer *models.Performer, data *models.PerformerEditData) error { if err := performer.ValidateModifyEdit(*data); err != nil { return err } return m.ApplyEdit(performer, false, data) } func (m *PerformerEditProcessor) applyDestroy(performer *models.Performer) error { _, err := m.SoftDelete(*performer) if err != nil { return err } if err = m.queries.DeletePerformerScenes(m.context, performer.ID); err != nil { return err } return m.queries.DeletePerformerFavorites(m.context, performer.ID) } func (m *PerformerEditProcessor) applyMerge(performer *models.Performer, data *models.PerformerEditData) error { if err := m.applyModify(performer, data); err != nil { return err } for _, sourceID := range data.MergeSources { if err := m.mergeInto(sourceID, performer.ID, data.SetMergeAliases); err != nil { return err } } return nil } func (m *PerformerEditProcessor) mergeInto(sourceID uuid.UUID, targetID uuid.UUID, setAliases bool) error { dbPerformer, err := m.queries.FindPerformer(m.context, sourceID) if err != nil { return fmt.Errorf("%w: source performer, %s: %w", ErrEntityNotFound, sourceID.String(), err) } dbTarget, err := m.queries.FindPerformer(m.context, targetID) if err != nil { return fmt.Errorf("%w: target performer %s, %w", ErrEntityNotFound, targetID.String(), err) } performer := converter.PerformerToModelPtr(dbPerformer) target := converter.PerformerToModelPtr(dbTarget) return m.MergeInto(performer, target, setAliases) } func bodyModCompare(subject []models.BodyModification, against []models.BodyModification) (added []models.BodyModification, missing []models.BodyModification) { for _, s := range subject { newMod := true for _, a := range against { if s.Location == a.Location { newMod = (s.Description != nil && a.Description != nil && *s.Description != *a.Description) || (s.Description == nil && a.Description != nil) || (a.Description == nil && s.Description != nil) } } for _, a := range added { if s.Location == a.Location { newMod = false } } if newMod { added = append(added, s) } } for _, s := range against { removedMod := true for _, a := range subject { if s.Location == a.Location { removedMod = (s.Description != nil && a.Description != nil && *s.Description != *a.Description) || (s.Description == nil && a.Description != nil) || (a.Description == nil && s.Description != nil) } } for _, a := range missing { if s.Location == a.Location { removedMod = false } } if removedMod { missing = append(missing, s) } } return } func (m *PerformerEditProcessor) diffRelationships(performerEdit *models.PerformerEditData, performerID uuid.UUID, input models.PerformerEditInput, inputArgs utils.ArgumentsQuery) error { if input.Details.Aliases != nil || inputArgs.Field("aliases").IsNull() { if err := m.diffAliases(performerEdit, performerID, input.Details.Aliases); err != nil { return err } } if input.Details.Tattoos != nil || inputArgs.Field("tattoos").IsNull() { if err := m.diffTattoos(performerEdit, performerID, converter.BodyModInputToModel(input.Details.Tattoos)); err != nil { return err } } if input.Details.Piercings != nil || inputArgs.Field("piercings").IsNull() { if err := m.diffPiercings(performerEdit, performerID, converter.BodyModInputToModel(input.Details.Piercings)); err != nil { return err } } if input.Details.Urls != nil || inputArgs.Field("urls").IsNull() { if err := m.diffURLs(performerEdit, performerID, input.Details.Urls); err != nil { return err } } if input.Details.ImageIds != nil || inputArgs.Field("image_ids").IsNull() { if err := m.diffImages(performerEdit, performerID, input.Details.ImageIds); err != nil { return err } } return nil } func (m *PerformerEditProcessor) diffAliases(performerEdit *models.PerformerEditData, performerID uuid.UUID, newAliases []string) error { aliases, err := m.queries.GetPerformerAliases(m.context, performerID) if err != nil { return err } performerEdit.New.AddedAliases, performerEdit.New.RemovedAliases = utils.SliceCompare(newAliases, aliases) return nil } func (m *PerformerEditProcessor) diffTattoos(performerEdit *models.PerformerEditData, performerID uuid.UUID, newTattoos []models.BodyModification) error { dbTattoos, err := m.queries.GetPerformerTattoos(m.context, performerID) if err != nil { return err } var tattoos []models.BodyModification for _, mod := range dbTattoos { newMod := models.BodyModification{ Description: mod.Description, } if mod.Location != nil { newMod.Location = *mod.Location } tattoos = append(tattoos, newMod) } performerEdit.New.AddedTattoos, performerEdit.New.RemovedTattoos = bodyModCompare(newTattoos, tattoos) return nil } func (m *PerformerEditProcessor) diffPiercings(performerEdit *models.PerformerEditData, performerID uuid.UUID, newPiercings []models.BodyModification) error { dbPiercings, err := m.queries.GetPerformerPiercings(m.context, performerID) if err != nil { return err } var piercings []models.BodyModification for _, mod := range dbPiercings { newMod := models.BodyModification{ Description: mod.Description, } if mod.Location != nil { newMod.Location = *mod.Location } piercings = append(piercings, newMod) } performerEdit.New.AddedPiercings, performerEdit.New.RemovedPiercings = bodyModCompare(newPiercings, piercings) return nil } func (m *PerformerEditProcessor) diffURLs(performerEdit *models.PerformerEditData, performerID uuid.UUID, newURLs []models.URL) error { dbUrls, err := m.queries.GetPerformerURLs(m.context, performerID) if err != nil { return err } var urls []models.URL for _, url := range dbUrls { urls = append(urls, models.URL{ URL: url.Url, SiteID: url.SiteID, }) } performerEdit.New.AddedUrls, performerEdit.New.RemovedUrls = urlCompare(newURLs, urls) return nil } func (m *PerformerEditProcessor) diffImages(performerEdit *models.PerformerEditData, performerID uuid.UUID, newImages []uuid.UUID) error { images, err := m.queries.GetPerformerImages(m.context, performerID) if err != nil { return err } var existingImages []uuid.UUID for _, image := range images { existingImages = append(existingImages, image.ID) } performerEdit.New.AddedImages, performerEdit.New.RemovedImages = utils.SliceCompare(newImages, existingImages) return nil } func (m *PerformerEditProcessor) SoftDelete(performer models.Performer) (*models.Performer, error) { // Delete joins if err := m.queries.DeletePerformerAliases(m.context, performer.ID); err != nil { return nil, err } if err := m.queries.DeletePerformerPiercings(m.context, performer.ID); err != nil { return nil, err } if err := m.queries.DeletePerformerTattoos(m.context, performer.ID); err != nil { return nil, err } if err := m.queries.DeletePerformerURLs(m.context, performer.ID); err != nil { return nil, err } if err := m.queries.DeletePerformerImages(m.context, performer.ID); err != nil { return nil, err } ret, err := m.queries.SoftDeletePerformer(m.context, performer.ID) return converter.PerformerToModelPtr(ret), err } func (m *PerformerEditProcessor) UpdateScenePerformers(oldPerformer *models.Performer, newTarget *models.Performer, setAliases bool) error { if setAliases { if err := m.UpdateScenePerformerAlias(oldPerformer.ID, oldPerformer.Name, newTarget.Name); err != nil { return err } } // Reassign scene performances to new performer, except if new performer is already assigned if err := m.queries.ReassignPerformerAliases(m.context, queries.ReassignPerformerAliasesParams{ OldPerformerID: oldPerformer.ID, NewPerformerID: newTarget.ID, }); err != nil { return err } // Delete leftover scene performances return m.queries.DeletePerformerScenes(m.context, oldPerformer.ID) } func (m *PerformerEditProcessor) reassignFavorites(oldPerformer *models.Performer, newTargetID uuid.UUID) error { if err := m.queries.ReassignPerformerFavorites(m.context, queries.ReassignPerformerFavoritesParams{ OldPerformerID: oldPerformer.ID, NewPerformerID: newTargetID, }); err != nil { return err } return m.queries.DeletePerformerFavorites(m.context, oldPerformer.ID) } func (m *PerformerEditProcessor) UpdateScenePerformerAlias(performerID uuid.UUID, oldName string, newName string) error { // Set old name as scene performance alias where one isn't already set if err := m.queries.SetScenePerformerAlias(m.context, queries.SetScenePerformerAliasParams{ PerformerID: performerID, As: &oldName, }); err != nil { return err } // Remove alias from scene performances where the alias matches new name return m.queries.ClearScenePerformerAlias(m.context, queries.ClearScenePerformerAliasParams{ PerformerID: performerID, As: &newName, }) } func (m *PerformerEditProcessor) MergeInto(source *models.Performer, target *models.Performer, setAliases bool) error { if source.Deleted { return fmt.Errorf("merge source performer is deleted: %s", source.ID.String()) } if target.Deleted { return fmt.Errorf("merge target performer is deleted: %s", target.ID.String()) } if _, err := m.SoftDelete(*source); err != nil { return err } if err := m.queries.UpdatePerformerRedirects(m.context, queries.UpdatePerformerRedirectsParams{ OldPerformerID: source.ID, NewPerformerID: target.ID, }); err != nil { return err } if err := m.UpdateScenePerformers(source, target, setAliases); err != nil { return err } if err := m.reassignFavorites(source, target.ID); err != nil { return err } return m.queries.CreatePerformerRedirect(m.context, queries.CreatePerformerRedirectParams{ SourceID: source.ID, TargetID: target.ID, }) } func (m *PerformerEditProcessor) ApplyEdit(performer *models.Performer, create bool, data *models.PerformerEditData) error { old := data.Old if old == nil { old = &models.PerformerEdit{} } performer.CopyFromPerformerEdit(*data.New, *old) var err error if create { _, err = m.queries.CreatePerformer(m.context, converter.PerformerToCreateParams(*performer)) } else { _, err = m.queries.UpdatePerformer(m.context, converter.PerformerToUpdateParams(*performer)) } if err != nil { return err } if err := m.updateAliasesFromEdit(performer.ID, data); err != nil { return err } if err := m.updateTattoosFromEdit(performer.ID, data); err != nil { return err } if err := m.updatePiercingsFromEdit(performer.ID, data); err != nil { return err } if err := m.updateURLsFromEdit(performer.ID, data); err != nil { return err } if err := m.updateImagesFromEdit(performer.ID, data); err != nil { return err } if data.New.Name != nil && data.SetModifyAliases { if err = m.UpdateScenePerformerAlias(performer.ID, *data.Old.Name, *data.New.Name); err != nil { return err } } return err } func (m *PerformerEditProcessor) updateAliasesFromEdit(performerID uuid.UUID, data *models.PerformerEditData) error { aliases, err := m.queries.GetEditPerformerAliases(m.context, m.edit.ID) if err != nil { return err } if err := m.queries.DeletePerformerAliases(m.context, performerID); err != nil { return err } var aliasParam []queries.CreatePerformerAliasesParams for _, alias := range aliases { aliasParam = append(aliasParam, queries.CreatePerformerAliasesParams{ Alias: alias, PerformerID: performerID, }) } _, err = m.queries.CreatePerformerAliases(m.context, aliasParam) return err } func (m *PerformerEditProcessor) updateTattoosFromEdit(performerID uuid.UUID, data *models.PerformerEditData) error { tattoos, err := m.queries.GetEditPerformerTattoos(m.context, m.edit.ID) if err != nil { return err } if err := m.queries.DeletePerformerTattoos(m.context, performerID); err != nil { return err } if len(tattoos) == 0 { return nil } var tattooParams []queries.CreatePerformerTattoosParams for _, tattoo := range tattoos { tattooParams = append(tattooParams, queries.CreatePerformerTattoosParams{ PerformerID: performerID, Location: tattoo.Location, Description: tattoo.Description, }) } _, err = m.queries.CreatePerformerTattoos(m.context, tattooParams) return err } func (m *PerformerEditProcessor) updatePiercingsFromEdit(performerID uuid.UUID, data *models.PerformerEditData) error { piercings, err := m.queries.GetEditPerformerPiercings(m.context, m.edit.ID) if err != nil { return err } if err := m.queries.DeletePerformerPiercings(m.context, performerID); err != nil { return err } if len(piercings) == 0 { return nil } var piercingParams []queries.CreatePerformerPiercingsParams for _, piercing := range piercings { piercingParams = append(piercingParams, queries.CreatePerformerPiercingsParams{ PerformerID: performerID, Location: piercing.Location, Description: piercing.Description, }) } _, err = m.queries.CreatePerformerPiercings(m.context, piercingParams) return err } func (m *PerformerEditProcessor) updateURLsFromEdit(performerID uuid.UUID, data *models.PerformerEditData) error { urls, err := m.queries.GetMergedURLsForEdit(m.context, m.edit.ID) if err != nil { return err } if err := m.queries.DeletePerformerURLs(m.context, performerID); err != nil { return err } var urlsParams []queries.CreatePerformerURLsParams for _, url := range urls { urlsParams = append(urlsParams, queries.CreatePerformerURLsParams{ PerformerID: performerID, Url: url.Url, SiteID: url.SiteID, }) } _, err = m.queries.CreatePerformerURLs(m.context, urlsParams) return err } func (m *PerformerEditProcessor) updateImagesFromEdit(performerID uuid.UUID, data *models.PerformerEditData) error { dbImages, err := m.queries.GetImagesForEdit(m.context, m.edit.ID) if err != nil { return err } if err := m.queries.DeletePerformerImages(m.context, performerID); err != nil { return err } var images []queries.CreatePerformerImagesParams for _, image := range dbImages { images = append(images, queries.CreatePerformerImagesParams{ ImageID: image.ID, PerformerID: performerID, }) } _, err = m.queries.CreatePerformerImages(m.context, images) return err } ================================================ FILE: internal/service/edit/query.go ================================================ package edit import ( "context" "encoding/json" "errors" "fmt" "strings" sq "github.com/Masterminds/squirrel" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/auth" "github.com/stashapp/stash-box/internal/converter" "github.com/stashapp/stash-box/internal/models" queryhelper "github.com/stashapp/stash-box/internal/service/query" ) func (s *Edit) QueryCount(ctx context.Context, filter models.EditQueryInput) (int, error) { user := auth.GetCurrentUser(ctx) psql := sq.StatementBuilder.PlaceholderFormat(sq.Dollar) query, err := s.buildEditQuery(psql, filter, user.ID, true) if err != nil { return 0, err } return queryhelper.ExecuteCount(ctx, query, s.queries.DB(), "QueryEditsCount") } func (s *Edit) QueryEdits(ctx context.Context, filter models.EditQueryInput) ([]models.Edit, error) { user := auth.GetCurrentUser(ctx) psql := sq.StatementBuilder.PlaceholderFormat(sq.Dollar) query, err := s.buildEditQuery(psql, filter, user.ID, false) if err != nil { return nil, err } // Apply sort sortField := "created_at" sortDir := "DESC" if filter.Sort != "" { sortField = strings.ToLower(filter.Sort.String()) } if filter.Direction != "" { sortDir = strings.ToUpper(filter.Direction.String()) } // Special handling for closed_at and updated_at - use created_at as fallback if filter.Sort == models.EditSortEnumClosedAt || filter.Sort == models.EditSortEnumUpdatedAt { query = query.OrderBy(fmt.Sprintf("COALESCE(edits.%s, edits.created_at) %s, edits.id %s", sortField, sortDir, sortDir)) } else { query = query.OrderBy(fmt.Sprintf("edits.%s %s, edits.id %s", sortField, sortDir, sortDir)) } // Apply pagination query = queryhelper.ApplyPagination(query, filter.Page, filter.PerPage) return queryhelper.ExecuteQuery(ctx, query, s.queries.DB(), converter.EditToModel, "QueryEdits") } func (s *Edit) buildEditQuery(psql sq.StatementBuilderType, filter models.EditQueryInput, userID uuid.UUID, forCount bool) (sq.SelectBuilder, error) { var query sq.SelectBuilder if forCount { query = psql.Select("COUNT(DISTINCT edits.id)").From("edits") } else { query = psql.Select("edits.*").From("edits") } // Filter by voted status if filter.Voted != nil && *filter.Voted != "" { switch *filter.Voted { case models.UserVotedFilterEnumNotVoted: query = query. LeftJoin("edit_votes ON edits.id = edit_votes.edit_id AND edit_votes.user_id = ?", userID). Where("edit_votes.user_id IS NULL") default: query = query. Join("edit_votes ON edits.id = edit_votes.edit_id"). Where(sq.Eq{"edit_votes.user_id": userID, "edit_votes.vote": filter.Voted.String()}) } } // Filter by target ID if filter.TargetID != nil { if filter.TargetType == nil || *filter.TargetType == "" { return query, errors.New("TargetType is required when TargetID filter is used") } jsonID, _ := json.Marshal(*filter.TargetID) targetType := strings.ToLower(filter.TargetType.String()) switch *filter.TargetType { case models.TargetTypeEnumPerformer: subquery := fmt.Sprintf(` edits.id IN ( SELECT id FROM edits E WHERE E.data->'merge_sources' @> ? UNION SELECT edit_id FROM %s_edits WHERE %s_id = ? UNION SELECT id FROM edits E WHERE jsonb_path_query_array(data, '$.new_data.added_performers[*].performer_id') @> ? AND E.status = 'PENDING' AND E.target_type = 'SCENE' )`, targetType, targetType) query = query.Where(sq.Expr(subquery, string(jsonID), *filter.TargetID, string(jsonID))) case models.TargetTypeEnumStudio: subquery := fmt.Sprintf(` edits.id IN ( SELECT id FROM edits E WHERE E.data->'merge_sources' @> ? UNION SELECT edit_id FROM %s_edits WHERE %s_id = ? UNION SELECT id FROM edits E WHERE E.status = 'PENDING' AND E.target_type = 'SCENE' AND E.data->'new_data'->'studio_id' @> ? )`, targetType, targetType) query = query.Where(sq.Expr(subquery, string(jsonID), *filter.TargetID, string(jsonID))) case models.TargetTypeEnumTag: subquery := fmt.Sprintf(` edits.id IN ( SELECT id FROM edits E WHERE E.data->'merge_sources' @> ? UNION SELECT edit_id FROM %s_edits WHERE %s_id = ? UNION SELECT id FROM edits E WHERE E.status = 'PENDING' AND E.target_type = 'SCENE' AND E.data->'new_data'->'added_tags' @> ? )`, targetType, targetType) query = query.Where(sq.Expr(subquery, string(jsonID), *filter.TargetID, string(jsonID))) default: subquery := fmt.Sprintf(` edits.id IN ( SELECT id FROM edits E WHERE E.data->'merge_sources' @> ? UNION SELECT edit_id FROM %s_edits WHERE %s_id = ? )`, targetType, targetType) query = query.Where(sq.Expr(subquery, string(jsonID), *filter.TargetID)) } } else if filter.TargetType != nil && *filter.TargetType != "" { query = query.Where(sq.Eq{"target_type": filter.TargetType.String()}) } // Filter by favorite status if filter.IsFavorite != nil && *filter.IsFavorite { favoriteClause := ` edits.id IN ( (SELECT TE.edit_id FROM studio_favorites TF JOIN studio_edits TE ON TF.studio_id = TE.studio_id WHERE TF.user_id = ?) UNION (SELECT PE.edit_id FROM performer_favorites PF JOIN performer_edits PE ON PF.performer_id = PE.performer_id WHERE PF.user_id = ?) UNION (SELECT SE.edit_id FROM studio_favorites TF JOIN scenes S ON TF.studio_id = S.studio_id JOIN scene_edits SE ON S.id = SE.scene_id WHERE TF.user_id = ?) UNION (SELECT E.id FROM performer_favorites PF JOIN edits E ON E.data->'merge_sources' @> to_jsonb(PF.performer_id::TEXT) WHERE E.target_type = 'PERFORMER' AND E.operation = 'MERGE' AND PF.user_id = ?) UNION (SELECT E.id FROM performer_favorites PF JOIN edits E ON jsonb_path_query_array(E.data, '$.new_data.added_performers[*].performer_id') @> to_jsonb(PF.performer_id::TEXT) OR jsonb_path_query_array(E.data, '$.new_data.removed_performers[*].performer_id') @> to_jsonb(PF.performer_id::TEXT) WHERE E.target_type = 'SCENE' AND PF.user_id = ?) UNION (SELECT E.id FROM studio_favorites TF JOIN edits E ON data->'new_data'->>'studio_id' = TF.studio_id::TEXT OR data->'old_data'->>'studio_id' = TF.studio_id::TEXT WHERE E.target_type = 'SCENE' AND TF.user_id = ?) ) ` query = query.Where(sq.Expr(favoriteClause, userID, userID, userID, userID, userID, userID)) } // Simple filters if filter.UserID != nil { query = query.Where(sq.Eq{"edits.user_id": *filter.UserID}) } if filter.Status != nil { query = query.Where(sq.Eq{"status": filter.Status.String()}) } if filter.Operation != nil { query = query.Where(sq.Eq{"operation": filter.Operation.String()}) } if filter.Applied != nil { query = query.Where(sq.Eq{"applied": *filter.Applied}) } if filter.IsBot != nil { query = query.Where(sq.Eq{"bot": *filter.IsBot}) } if filter.IncludeUserSubmitted != nil && !*filter.IncludeUserSubmitted { query = query.Where(sq.NotEq{"edits.user_id": userID}) } return query, nil } ================================================ FILE: internal/service/edit/scene.go ================================================ package edit import ( "context" "errors" "fmt" "reflect" "github.com/gofrs/uuid" "github.com/jackc/pgx/v5" "github.com/stashapp/stash-box/internal/converter" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/internal/queries" "github.com/stashapp/stash-box/pkg/utils" ) type SceneEditProcessor struct { mutator } func Scene(ctx context.Context, queries *queries.Queries, edit *models.Edit) *SceneEditProcessor { return &SceneEditProcessor{ mutator{ context: ctx, queries: queries, edit: edit, }, } } func (m *SceneEditProcessor) Edit(input models.SceneEditInput, inputArgs utils.ArgumentsQuery, update bool) error { if err := validateSceneEditInput(m.context, m.queries, input, m.edit, update); err != nil { return err } var err error switch input.Edit.Operation { case models.OperationEnumModify: err = m.modifyEdit(input, inputArgs) case models.OperationEnumMerge: err = m.mergeEdit(input, inputArgs) case models.OperationEnumDestroy: err = m.destroyEdit(input, inputArgs) case models.OperationEnumCreate: err = m.createEdit(input, inputArgs) } return err } func (m *SceneEditProcessor) modifyEdit(input models.SceneEditInput, inputArgs utils.ArgumentsQuery) error { // get the existing scene sceneID := *input.Edit.ID dbScene, err := m.queries.FindScene(m.context, sceneID) if err != nil { return err } scene := converter.SceneToModel(dbScene) var entity editEntity = scene if err := validateEditEntity(&entity, sceneID, "scene"); err != nil { return err } // perform a diff against the input and the current object detailArgs := inputArgs.Field("details") sceneEdit, err := input.Details.SceneEditFromDiff(scene, detailArgs) if err != nil { return err } if err = m.diffRelationships(sceneEdit, sceneID, input, inputArgs); err != nil { return err } if reflect.DeepEqual(sceneEdit.Old, sceneEdit.New) { return ErrNoChanges } sceneEdit.New.DraftID = input.Details.DraftID return m.edit.SetData(*sceneEdit) } func (m *SceneEditProcessor) diffRelationships(sceneEdit *models.SceneEditData, sceneID uuid.UUID, input models.SceneEditInput, inputArgs utils.ArgumentsQuery) error { if input.Details.Urls != nil || inputArgs.Field("urls").IsNull() { if err := m.diffURLs(sceneEdit, sceneID, input.Details.Urls); err != nil { return err } } if input.Details.TagIds != nil || inputArgs.Field("tag_ids").IsNull() { if err := m.diffTags(sceneEdit, sceneID, input.Details.TagIds); err != nil { return err } } if input.Details.ImageIds != nil || inputArgs.Field("image_ids").IsNull() { if err := m.diffImages(sceneEdit, sceneID, input.Details.ImageIds); err != nil { return err } } if input.Details.Performers != nil || inputArgs.Field("performers").IsNull() { if err := m.diffPerformers(sceneEdit, sceneID, input.Details.Performers); err != nil { return err } } return nil } func (m *SceneEditProcessor) diffTags(sceneEdit *models.SceneEditData, sceneID uuid.UUID, newImageIds []uuid.UUID) error { tags, err := m.queries.FindTagsBySceneID(m.context, sceneID) if err != nil { return err } var existingTags []uuid.UUID for _, tag := range tags { existingTags = append(existingTags, tag.ID) } sceneEdit.New.AddedTags, sceneEdit.New.RemovedTags = utils.SliceCompare(newImageIds, existingTags) return nil } func (m *SceneEditProcessor) diffURLs(sceneEdit *models.SceneEditData, sceneID uuid.UUID, newURLs []models.URL) error { dbUrls, err := m.queries.GetSceneURLs(m.context, sceneID) if err != nil { return err } var urls []models.URL for _, url := range dbUrls { urls = append(urls, models.URL{ URL: url.Url, SiteID: url.SiteID, }) } sceneEdit.New.AddedUrls, sceneEdit.New.RemovedUrls = urlCompare(newURLs, urls) return nil } func (m *SceneEditProcessor) diffPerformers(sceneEdit *models.SceneEditData, sceneID uuid.UUID, newPerformers []models.PerformerAppearanceInput) error { existingPerformers, err := m.queries.GetScenePerformers(m.context, sceneID) if err != nil { return err } sceneEdit.New.AddedPerformers, sceneEdit.New.RemovedPerformers = performerAppearanceCompare(newPerformers, existingPerformers) return nil } func performerAppearanceCompare(subject []models.PerformerAppearanceInput, against []queries.GetScenePerformersRow) (added []models.PerformerAppearanceInput, missing []models.PerformerAppearanceInput) { eq := func(s models.PerformerAppearanceInput, a queries.GetScenePerformersRow) bool { if s.PerformerID == a.Performer.ID { sAs := "" if s.As != nil { sAs = *s.As } aAs := "" if a.As != nil { aAs = *a.As } return sAs == aAs } return false } eqI := func(s, a models.PerformerAppearanceInput) bool { if s.PerformerID == a.PerformerID { if s.As == a.As { return true } if s.As == nil || a.As == nil { return false } return *s.As == *a.As } return false } for _, s := range subject { newMod := true for _, a := range against { if eq(s, a) { newMod = false } } for _, a := range added { if eqI(s, a) { newMod = false } } if newMod { added = append(added, s) } } for _, s := range against { removedMod := true for _, a := range subject { if eq(a, s) { removedMod = false } } for _, a := range missing { if eq(a, s) { removedMod = false } } if removedMod { missing = append(missing, models.PerformerAppearanceInput{ PerformerID: s.Performer.ID, As: s.As, }) } } return } func (m *SceneEditProcessor) diffImages(sceneEdit *models.SceneEditData, sceneID uuid.UUID, newImageIds []uuid.UUID) error { images, err := m.queries.FindImagesBySceneID(m.context, sceneID) if err != nil { return err } var existingImages []uuid.UUID for _, image := range images { existingImages = append(existingImages, image.ID) } sceneEdit.New.AddedImages, sceneEdit.New.RemovedImages = utils.SliceCompare(newImageIds, existingImages) return nil } func (m *SceneEditProcessor) mergeEdit(input models.SceneEditInput, inputArgs utils.ArgumentsQuery) error { // get the existing scene if input.Edit.ID == nil { return ErrMergeIDMissing } sceneID := *input.Edit.ID dbScene, err := m.queries.FindScene(m.context, sceneID) if err != nil { return fmt.Errorf("%w: target scene, %s: %w", ErrEntityNotFound, sceneID.String(), err) } scene := converter.SceneToModel(dbScene) var mergeSources []uuid.UUID for _, sourceID := range input.Edit.MergeSourceIds { _, err := m.queries.FindScene(m.context, sourceID) if err != nil { return fmt.Errorf("%w: source scene, %s: %w", ErrEntityNotFound, sourceID.String(), err) } if sceneID == sourceID { return ErrMergeTargetIsSource } mergeSources = append(mergeSources, sourceID) } if len(mergeSources) < 1 { return ErrNoMergeSources } // perform a diff against the input and the current object detailArgs := inputArgs.Field("details") sceneEdit, err := input.Details.SceneEditFromMerge(scene, mergeSources, detailArgs) if err != nil { return err } if err = m.diffRelationships(sceneEdit, sceneID, input, inputArgs); err != nil { return err } return m.edit.SetData(*sceneEdit) } func (m *SceneEditProcessor) createEdit(input models.SceneEditInput, inputArgs utils.ArgumentsQuery) error { sceneEdit, err := input.Details.SceneEditFromCreate(inputArgs) if err != nil { return err } sceneEdit.New.AddedUrls = input.Details.Urls sceneEdit.New.AddedTags = input.Details.TagIds sceneEdit.New.AddedImages = input.Details.ImageIds sceneEdit.New.AddedPerformers = input.Details.Performers sceneEdit.New.AddedFingerprints = input.Details.Fingerprints sceneEdit.New.DraftID = input.Details.DraftID return m.edit.SetData(*sceneEdit) } func (m *SceneEditProcessor) destroyEdit(input models.SceneEditInput, inputArgs utils.ArgumentsQuery) error { // get the existing scene sceneID := *input.Edit.ID dbScene, err := m.queries.FindScene(m.context, sceneID) if err != nil { return err } var entity editEntity = converter.SceneToModel(dbScene) return validateEditEntity(&entity, sceneID, "scene") } func (m *SceneEditProcessor) CreateJoin(input models.SceneEditInput) error { if input.Edit.ID != nil { return m.queries.CreateSceneEdit(m.context, queries.CreateSceneEditParams{ EditID: m.edit.ID, SceneID: *input.Edit.ID, }) } return nil } func (m *SceneEditProcessor) apply() error { operation := m.operation() isCreate := operation == models.OperationEnumCreate var scene *models.Scene if !isCreate { res, err := m.queries.GetEditTargetID(m.context, m.edit.ID) if err != nil { return err } dbScene, err := m.queries.FindScene(m.context, res.ID) if err != nil { return fmt.Errorf("%w: scene, %s: %w", ErrEntityNotFound, res.ID.String(), err) } scene = converter.SceneToModelPtr(dbScene) } return m.applyEdit(scene) } func (m *SceneEditProcessor) applyEdit(scene *models.Scene) error { data, err := m.edit.GetSceneData() if err != nil { return err } operation := m.operation() switch operation { case models.OperationEnumCreate: var userID *uuid.UUID if m.edit.UserID.Valid { userID = &m.edit.UserID.UUID } return m.applyCreate(data, userID) case models.OperationEnumDestroy: return m.applyDestroy(scene) case models.OperationEnumModify: return m.applyModify(scene, data) case models.OperationEnumMerge: return m.applyMerge(scene, data) } return nil } func (m *SceneEditProcessor) applyCreate(data *models.SceneEditData, userID *uuid.UUID) error { UUID := data.New.DraftID if UUID == nil { newUUID, err := uuid.NewV7() if err != nil { return err } UUID = &newUUID } newScene := &models.Scene{ ID: *UUID, } if err := m.ApplyEdit(newScene, true, data, userID); err != nil { return err } return m.queries.CreateSceneEdit(m.context, queries.CreateSceneEditParams{ EditID: m.edit.ID, SceneID: newScene.ID, }) } func (m *SceneEditProcessor) applyModify(scene *models.Scene, data *models.SceneEditData) error { if err := scene.ValidateModifyEdit(*data); err != nil { return err } return m.ApplyEdit(scene, false, data, nil) } func (m *SceneEditProcessor) applyDestroy(scene *models.Scene) error { _, err := m.queries.SoftDeleteScene(m.context, scene.ID) if err != nil { return err } // delete relationships if err = m.queries.DeleteSceneTagsByScene(m.context, scene.ID); err != nil { return err } if err = m.queries.DeleteScenePerformers(m.context, scene.ID); err != nil { return err } return err } func (m *SceneEditProcessor) applyMerge(scene *models.Scene, data *models.SceneEditData) error { if err := m.applyModify(scene, data); err != nil { return err } for _, sourceID := range data.MergeSources { if err := m.mergeInto(sourceID, scene.ID); err != nil { return err } } return nil } func (m *SceneEditProcessor) mergeInto(sourceID uuid.UUID, targetID uuid.UUID) error { scene, err := m.queries.FindScene(m.context, sourceID) if err != nil { return fmt.Errorf("%w: source scene, %s: %w", ErrEntityNotFound, sourceID.String(), err) } target, err := m.queries.FindScene(m.context, targetID) if err != nil { return fmt.Errorf("%w: target scene, %s: %w", ErrEntityNotFound, targetID.String(), err) } return m.MergeInto(scene, target) } func (m *SceneEditProcessor) ApplyEdit(scene *models.Scene, create bool, data *models.SceneEditData, userID *uuid.UUID) error { old := data.Old if old == nil { old = &models.SceneEdit{} } scene.CopyFromSceneEdit(*data.New, old) var err error if create { newScene := converter.SceneToCreateParams(*scene) _, err = m.queries.CreateScene(m.context, newScene) } else { updateScene := converter.SceneToUpdateParams(*scene) _, err = m.queries.UpdateScene(m.context, updateScene) } if err != nil { return err } if err := m.updateURLsFromEdit(scene, data); err != nil { return err } if err := m.updateImagesFromEdit(scene, data); err != nil { return err } if err := m.updateTagsFromEdit(scene, data); err != nil { return err } if err := m.updatePerformersFromEdit(scene, data); err != nil { return err } if create && len(data.New.AddedFingerprints) > 0 && userID != nil { if err := m.addFingerprintsFromEdit(scene, data, *userID); err != nil { return err } } return err } func (m *SceneEditProcessor) updateURLsFromEdit(scene *models.Scene, data *models.SceneEditData) error { urls, err := m.queries.GetMergedURLsForEdit(m.context, m.edit.ID) if err != nil { return err } if err := m.queries.DeleteSceneURLs(m.context, scene.ID); err != nil { return err } var urlsParams []queries.CreateSceneURLsParams for _, url := range urls { urlsParams = append(urlsParams, queries.CreateSceneURLsParams{ SceneID: scene.ID, Url: url.Url, SiteID: url.SiteID, }) } _, err = m.queries.CreateSceneURLs(m.context, urlsParams) return err } func (m *SceneEditProcessor) updateImagesFromEdit(scene *models.Scene, data *models.SceneEditData) error { images, err := m.queries.GetImagesForEdit(m.context, m.edit.ID) if err != nil { return err } if err := m.queries.DeleteSceneImages(m.context, scene.ID); err != nil { return err } var sceneImages []queries.CreateSceneImagesParams for _, image := range images { sceneImages = append(sceneImages, queries.CreateSceneImagesParams{ ImageID: image.ID, SceneID: scene.ID, }) } _, err = m.queries.CreateSceneImages(m.context, sceneImages) return err } func (m *SceneEditProcessor) updateTagsFromEdit(scene *models.Scene, data *models.SceneEditData) error { tags, err := m.queries.GetMergedTagsForEdit(m.context, m.edit.ID) if err != nil { return err } if err := m.queries.DeleteSceneTagsByScene(m.context, scene.ID); err != nil { return nil } var sceneTags []queries.CreateSceneTagsParams for _, tag := range tags { sceneTags = append(sceneTags, queries.CreateSceneTagsParams{ TagID: tag.ID, SceneID: scene.ID, }) } _, err = m.queries.CreateSceneTags(m.context, sceneTags) return err } func (m *SceneEditProcessor) updatePerformersFromEdit(scene *models.Scene, data *models.SceneEditData) error { appearances, err := m.queries.GetMergedPerformersForEdit(m.context, m.edit.ID) if err != nil { return err } if err := m.queries.DeleteScenePerformers(m.context, scene.ID); err != nil { return err } var scenePerformers []queries.CreateScenePerformersParams for _, appearance := range appearances { scenePerformers = append(scenePerformers, queries.CreateScenePerformersParams{ PerformerID: appearance.Performer.ID, As: appearance.As, SceneID: scene.ID, }) } _, err = m.queries.CreateScenePerformers(m.context, scenePerformers) return err } func (m *SceneEditProcessor) addFingerprintsFromEdit(scene *models.Scene, data *models.SceneEditData, userID uuid.UUID) error { var params []queries.CreateSceneFingerprintsParams for _, fingerprint := range data.New.AddedFingerprints { if fingerprint.Duration > 0 { id, err := m.getOrCreateFingerprintID(fingerprint.Hash, fingerprint.Algorithm.String()) if err != nil { return err } params = append(params, queries.CreateSceneFingerprintsParams{ FingerprintID: int(id), SceneID: scene.ID, UserID: userID, Duration: fingerprint.Duration, }) } } if len(params) > 0 { _, err := m.queries.CreateSceneFingerprints(m.context, params) return err } return nil } func (m *SceneEditProcessor) getOrCreateFingerprintID(hash models.FingerprintHash, algorithm string) (int, error) { fp, err := m.queries.GetFingerprint(m.context, queries.GetFingerprintParams{ Hash: hash.Int64(), Algorithm: algorithm, }) if err == nil { return fp.ID, nil } if !errors.Is(err, pgx.ErrNoRows) { return 0, err } newFp, err := m.queries.CreateFingerprint(m.context, queries.CreateFingerprintParams{ Hash: hash.Int64(), Algorithm: algorithm, }) if err != nil { return 0, err } return newFp.ID, nil } func (m *SceneEditProcessor) MergeInto(source queries.Scene, target queries.Scene) error { if source.Deleted { return fmt.Errorf("merge source scene is deleted: %s", source.ID.String()) } if target.Deleted { return fmt.Errorf("merge target scene is deleted: %s", target.ID.String()) } if _, err := m.queries.SoftDeleteScene(m.context, source.ID); err != nil { return err } if err := m.queries.UpdateSceneRedirects(m.context, queries.UpdateSceneRedirectsParams{ OldTargetID: source.ID, NewTargetID: target.ID, }); err != nil { return err } return m.queries.CreateSceneRedirect(m.context, queries.CreateSceneRedirectParams{ SourceID: source.ID, TargetID: target.ID, }) } ================================================ FILE: internal/service/edit/service.go ================================================ package edit import ( "context" "encoding/json" "errors" "fmt" "slices" "time" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/auth" "github.com/stashapp/stash-box/internal/config" "github.com/stashapp/stash-box/internal/converter" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/internal/models/validator" "github.com/stashapp/stash-box/internal/queries" "github.com/stashapp/stash-box/internal/service/errutil" "github.com/stashapp/stash-box/pkg/logger" "github.com/stashapp/stash-box/pkg/utils" ) var ErrUnauthorizedUpdate = fmt.Errorf("only the creator can update edits") var ErrClosedEdit = fmt.Errorf("votes can only be cast on pending edits") var ErrUnauthorizedBot = fmt.Errorf("you do not have permission to submit bot edits") var ErrUpdateLimit = fmt.Errorf("edit update limit reached") var ErrSceneDraftRequired = fmt.Errorf("scenes have to be submitted through drafts") var ErrPendingEdit = fmt.Errorf("cannot delete pending edit - only closed edits can be deleted") var ErrAmendPendingEdit = fmt.Errorf("cannot amend pending edit - only closed edits can be amended") var ErrNoChangesToAmend = fmt.Errorf("must specify at least one field or item to remove") var ErrAmendEmptyResult = fmt.Errorf("cannot remove all fields - edit must retain some content") // Edit handles edit-related operations type Edit struct { queries *queries.Queries withTxn queries.WithTxnFunc } // NewEdit creates a new edit service func NewEdit(queries *queries.Queries, withTxn queries.WithTxnFunc) *Edit { return &Edit{ queries: queries, withTxn: withTxn, } } func (s *Edit) FindByID(ctx context.Context, id uuid.UUID) (*models.Edit, error) { edit, err := s.queries.FindEdit(ctx, id) if err != nil { return nil, errutil.IgnoreNotFound(err) } return converter.EditToModelPtr(edit), nil } func (s *Edit) GetComments(ctx context.Context, editID uuid.UUID) ([]models.EditComment, error) { comments, err := s.queries.GetEditComments(ctx, editID) if err != nil { return nil, err } return converter.EditCommentsToModels(comments), nil } func (s *Edit) GetVotes(ctx context.Context, editID uuid.UUID) ([]models.EditVote, error) { votes, err := s.queries.GetEditVotes(ctx, editID) if err != nil { return nil, err } return converter.EditVotesToModels(votes), nil } func (s *Edit) Delete(ctx context.Context, id uuid.UUID) (bool, error) { err := s.queries.DeleteEdit(ctx, id) if err != nil { return false, err } return true, nil } // DeleteWithAudit deletes a closed edit and creates an audit record func (s *Edit) DeleteWithAudit(ctx context.Context, input models.DeleteEditInput) error { currentUser := auth.GetCurrentUser(ctx) if currentUser == nil { return fmt.Errorf("no authenticated user found") } return s.withTxn(func(tx *queries.Queries) error { // Fetch the edit to verify it exists and is closed dbEdit, err := tx.FindEdit(ctx, input.ID) if err != nil { return fmt.Errorf("failed to find edit: %w", err) } // Verify edit is closed if dbEdit.ClosedAt == nil { return ErrPendingEdit } // Only create audit log if retention is enabled (> 0 days) retentionDays := config.GetModAuditRetentionDays() if retentionDays > 0 { // Create audit data with complete edit record auditData := struct { queries.Edit DeletedBy uuid.UUID `json:"deleted_by"` DeletedAt time.Time `json:"deleted_at"` }{ Edit: dbEdit, DeletedBy: currentUser.ID, DeletedAt: time.Now(), } // Marshal audit data to JSON auditDataJSON, err := json.Marshal(auditData) if err != nil { return fmt.Errorf("failed to marshal audit data: %w", err) } // Create mod_audit record auditID, err := uuid.NewV7() if err != nil { return fmt.Errorf("failed to generate audit ID: %w", err) } _, err = tx.CreateModAudit(ctx, queries.CreateModAuditParams{ ID: auditID, Action: queries.ModAuditActionEDITDELETE, UserID: uuid.NullUUID{UUID: currentUser.ID, Valid: true}, TargetID: dbEdit.ID, TargetType: "EDIT", Data: auditDataJSON, Reason: &input.Reason, }) if err != nil { return fmt.Errorf("failed to create audit record: %w", err) } } // Delete the edit (cascades to comments and votes) if err := tx.DeleteEdit(ctx, input.ID); err != nil { return fmt.Errorf("failed to delete edit: %w", err) } return nil }) } // AmendEdit amends a closed edit by removing specified fields/items from the edit data func (s *Edit) AmendEdit(ctx context.Context, input models.AmendEditInput) (*models.Edit, error) { currentUser := auth.GetCurrentUser(ctx) if currentUser == nil { return nil, fmt.Errorf("no authenticated user found") } if len(input.RemoveFields) == 0 && len(input.RemoveAddedItems) == 0 && len(input.RemoveRemovedItems) == 0 { return nil, ErrNoChangesToAmend } var updatedEdit *models.Edit err := s.withTxn(func(tx *queries.Queries) error { dbEdit, err := tx.FindEdit(ctx, input.ID) if err != nil { return fmt.Errorf("failed to find edit: %w", err) } if dbEdit.ClosedAt == nil { return ErrAmendPendingEdit } var editData map[string]interface{} if err := json.Unmarshal(dbEdit.Data, &editData); err != nil { return fmt.Errorf("failed to parse edit data: %w", err) } newData, _ := editData["new_data"].(map[string]interface{}) oldData, _ := editData["old_data"].(map[string]interface{}) removedData := make(map[string]interface{}) // Remove scalar fields for _, field := range input.RemoveFields { if val, exists := newData[field]; exists { removedData[field] = val delete(newData, field) } delete(oldData, field) } // Remove array items for _, removal := range input.RemoveAddedItems { removeArrayItems(newData, "added_"+removal.Field, removal.Indices, removedData) } for _, removal := range input.RemoveRemovedItems { removeArrayItems(newData, "removed_"+removal.Field, removal.Indices, removedData) } if len(newData) == 0 { return ErrAmendEmptyResult } updatedData, err := json.Marshal(editData) if err != nil { return fmt.Errorf("failed to marshal updated edit data: %w", err) } if config.GetModAuditRetentionDays() > 0 { if err := s.createAmendAudit(ctx, tx, dbEdit.ID, currentUser.ID, input.Reason, removedData); err != nil { return err } } dbEdit, err = tx.UpdateEditData(ctx, queries.UpdateEditDataParams{ ID: input.ID, Data: updatedData, }) if err != nil { return fmt.Errorf("failed to update edit data: %w", err) } updatedEdit = converter.EditToModelPtr(dbEdit) return nil }) return updatedEdit, err } func (s *Edit) createAmendAudit(ctx context.Context, tx *queries.Queries, editID, userID uuid.UUID, reason string, removedData map[string]interface{}) error { removedDataJSON, err := json.Marshal(removedData) if err != nil { return fmt.Errorf("failed to marshal removed data: %w", err) } auditDataJSON, err := json.Marshal(models.EditAmendmentAuditData{ EditID: editID, AmendedBy: userID, AmendedAt: time.Now(), RemovedData: removedDataJSON, }) if err != nil { return fmt.Errorf("failed to marshal audit data: %w", err) } auditID, err := uuid.NewV7() if err != nil { return fmt.Errorf("failed to generate audit ID: %w", err) } _, err = tx.CreateModAudit(ctx, queries.CreateModAuditParams{ ID: auditID, Action: queries.ModAuditActionEDITAMENDMENT, UserID: uuid.NullUUID{UUID: userID, Valid: true}, TargetID: editID, TargetType: "EDIT", Data: auditDataJSON, Reason: &reason, }) if err != nil { return fmt.Errorf("failed to create audit record: %w", err) } return nil } func removeArrayItems(data map[string]interface{}, field string, indices []int, removed map[string]interface{}) { arr, ok := data[field].([]interface{}) if !ok { return } // Collect removed items var removedItems []interface{} for _, idx := range indices { if idx >= 0 && idx < len(arr) { removedItems = append(removedItems, arr[idx]) } } if len(removedItems) > 0 { removed[field] = removedItems } // Sort descending and remove slices.SortFunc(indices, func(a, b int) int { return b - a }) for _, idx := range indices { if idx >= 0 && idx < len(arr) { arr = slices.Delete(arr, idx, idx+1) } } if len(arr) == 0 { delete(data, field) } else { data[field] = arr } } func (s *Edit) GetEditTarget(ctx context.Context, id uuid.UUID) (models.EditTarget, error) { res, err := s.queries.GetEditTargetID(ctx, id) if err != nil { return nil, err } if res.ID.IsNil() { return nil, fmt.Errorf("target id not found") } switch res.TargetType { case models.TargetTypeEnumTag.String(): tag, err := s.queries.FindTag(ctx, res.ID) if err != nil { return nil, err } return converter.TagToModelPtr(tag), nil case models.TargetTypeEnumPerformer.String(): performer, err := s.queries.FindPerformer(ctx, res.ID) if err != nil { return nil, err } return converter.PerformerToModelPtr(performer), nil case models.TargetTypeEnumStudio.String(): studio, err := s.queries.FindStudio(ctx, res.ID) if err != nil { return nil, err } return converter.StudioToModelPtr(studio), nil case models.TargetTypeEnumScene.String(): scene, err := s.queries.FindScene(ctx, res.ID) if err != nil { return nil, err } return converter.SceneToModelPtr(scene), nil default: return nil, errors.New("not implemented") } } func (s *Edit) GetMergeSources(ctx context.Context, mergeIDs []uuid.UUID, targetType string) ([]models.EditTarget, error) { mergeSources := []models.EditTarget{} switch targetType { case models.TargetTypeEnumTag.String(): tags, err := s.queries.FindTagsByIds(ctx, mergeIDs) if err != nil { return nil, err } for _, tag := range tags { mergeSources = append(mergeSources, converter.TagToModelPtr(tag)) } case models.TargetTypeEnumPerformer.String(): performers, err := s.queries.FindPerformersByIds(ctx, mergeIDs) if err != nil { return nil, err } for _, performer := range performers { mergeSources = append(mergeSources, converter.PerformerToModelPtr(performer)) } case models.TargetTypeEnumStudio.String(): studios, err := s.queries.GetStudios(ctx, mergeIDs) if err != nil { return nil, err } for _, studio := range studios { mergeSources = append(mergeSources, converter.StudioToModelPtr(studio)) } case models.TargetTypeEnumScene.String(): scenes, err := s.queries.GetScenes(ctx, mergeIDs) if err != nil { return nil, err } for _, scene := range scenes { mergeSources = append(mergeSources, converter.SceneToModelPtr(scene)) } default: return nil, errors.New("not implemented") } return mergeSources, nil } func (s *Edit) GetMergedURLs(ctx context.Context, id uuid.UUID) ([]models.URL, error) { res, err := s.queries.GetMergedURLsForEdit(ctx, id) if err != nil { return nil, err } var urls []models.URL for _, url := range res { u := models.URL{URL: url.Url, SiteID: url.SiteID} urls = append(urls, u) } return urls, nil } func (s *Edit) GetMergedImages(ctx context.Context, id uuid.UUID) ([]models.Image, error) { res, err := s.queries.GetImagesForEdit(ctx, id) if err != nil { return nil, err } return converter.ImagesToModels(res), nil } func (s *Edit) GetMergedPerformerAliases(ctx context.Context, id uuid.UUID) ([]string, error) { return s.queries.GetEditPerformerAliases(ctx, id) } func (s *Edit) GetMergedStudioAliases(ctx context.Context, id uuid.UUID) ([]string, error) { return s.queries.GetMergedStudioAliasesForEdit(ctx, id) } func (s *Edit) GetMergedPerformerTattoos(ctx context.Context, id uuid.UUID) ([]models.BodyModification, error) { res, err := s.queries.GetEditPerformerTattoos(ctx, id) if err != nil { return nil, err } var mods []models.BodyModification for _, mod := range res { location := "" if mod.Location != nil { location = *mod.Location } bodyMod := models.BodyModification{ Location: location, Description: mod.Description, } mods = append(mods, bodyMod) } return mods, err } func (s *Edit) GetMergedPerformerPiercings(ctx context.Context, id uuid.UUID) ([]models.BodyModification, error) { res, err := s.queries.GetEditPerformerPiercings(ctx, id) if err != nil { return nil, err } var mods []models.BodyModification for _, mod := range res { location := "" if mod.Location != nil { location = *mod.Location } bodyMod := models.BodyModification{ Location: location, Description: mod.Description, } mods = append(mods, bodyMod) } return mods, err } func (s *Edit) GetMergedTags(ctx context.Context, id uuid.UUID) ([]models.Tag, error) { tags, err := s.queries.GetMergedTagsForEdit(ctx, id) if err != nil { return nil, err } return converter.TagsToModels(tags), nil } func (s *Edit) GetMergedPerformers(ctx context.Context, id uuid.UUID) ([]models.PerformerAppearance, error) { performers, err := s.queries.GetMergedPerformersForEdit(ctx, id) if err != nil { return nil, err } var result []models.PerformerAppearance for _, performer := range performers { convertedPerformer := converter.PerformerToModelPtr(performer.Performer) result = append(result, models.PerformerAppearance{ Performer: convertedPerformer, As: performer.As, }) } return result, nil } func (s *Edit) FindByPerformerID(ctx context.Context, performerID uuid.UUID) ([]models.Edit, error) { edits, err := s.queries.GetEditsByPerformer(ctx, performerID) if err != nil { return nil, err } var modelEdits []models.Edit for _, edit := range edits { modelEdits = append(modelEdits, converter.EditToModel(edit)) } return modelEdits, nil } func (s *Edit) FindByStudioID(ctx context.Context, studioID uuid.UUID) ([]models.Edit, error) { edits, err := s.queries.GetEditsByStudio(ctx, studioID) if err != nil { return nil, err } var modelEdits []models.Edit for _, edit := range edits { modelEdits = append(modelEdits, converter.EditToModel(edit)) } return modelEdits, nil } func (s *Edit) FindByTagID(ctx context.Context, tagID uuid.UUID) ([]models.Edit, error) { edits, err := s.queries.GetEditsByTag(ctx, tagID) if err != nil { return nil, err } var modelEdits []models.Edit for _, edit := range edits { modelEdits = append(modelEdits, converter.EditToModel(edit)) } return modelEdits, nil } func (s *Edit) FindBySceneID(ctx context.Context, sceneID uuid.UUID) ([]models.Edit, error) { edits, err := s.queries.GetEditsByScene(ctx, sceneID) if err != nil { return nil, err } var modelEdits []models.Edit for _, edit := range edits { modelEdits = append(modelEdits, converter.EditToModel(edit)) } return modelEdits, nil } func (s *Edit) CreateSceneEdit(ctx context.Context, input models.SceneEditInput) (*models.Edit, error) { UUID, err := uuid.NewV7() if err != nil { return nil, err } currentUser := auth.GetCurrentUser(ctx) if err := validateBotEdit(ctx, input.Edit); err != nil { return nil, err } newEdit := models.NewEdit(UUID, currentUser, models.TargetTypeEnumScene, input.Edit) // For scene create, check if draft exist if draft is required if config.GetRequireSceneDraft() && input.Edit.Operation == models.OperationEnumCreate { if input.Details != nil && input.Details.DraftID != nil { _, err := s.queries.FindDraft(ctx, *input.Details.DraftID) if err != nil { return nil, ErrSceneDraftRequired } } else { return nil, ErrSceneDraftRequired } } err = s.withTxn(func(tx *queries.Queries) error { p := Scene(ctx, tx, newEdit) inputArgs := utils.Arguments(ctx).Field("input") if err := p.Edit(input, inputArgs, false); err != nil { return err } newEdit, err = p.CreateEdit() if err != nil { return err } if err := p.CreateJoin(input); err != nil { return err } if input.Details != nil && input.Details.DraftID != nil { if err := tx.DeleteDraft(ctx, *input.Details.DraftID); err != nil { return err } } return p.CreateComment(currentUser, input.Edit.Comment) }) return newEdit, err } func (s *Edit) UpdateSceneEdit(ctx context.Context, id uuid.UUID, input models.SceneEditInput) (*models.Edit, error) { currentUser := auth.GetCurrentUser(ctx) dbEdit, err := s.queries.FindEdit(ctx, id) if err != nil { return nil, err } edit := converter.EditToModelPtr(dbEdit) if err = validateEditUpdate(*edit, currentUser); err != nil { return nil, err } err = s.withTxn(func(tx *queries.Queries) error { p := Scene(ctx, tx, edit) inputArgs := utils.Arguments(ctx).Field("input") if err := p.Edit(input, inputArgs, true); err != nil { return err } edit, err = p.UpdateEdit() if err != nil { return err } return p.CreateComment(currentUser, input.Edit.Comment) }) return edit, err } func (s *Edit) CreateStudioEdit(ctx context.Context, input models.StudioEditInput) (*models.Edit, error) { UUID, err := uuid.NewV7() if err != nil { return nil, err } // create the edit currentUser := auth.GetCurrentUser(ctx) if err := validateBotEdit(ctx, input.Edit); err != nil { return nil, err } newEdit := models.NewEdit(UUID, currentUser, models.TargetTypeEnumStudio, input.Edit) err = s.withTxn(func(tx *queries.Queries) error { p := Studio(ctx, tx, newEdit) inputArgs := utils.Arguments(ctx).Field("input") if err := p.Edit(input, inputArgs); err != nil { return err } newEdit, err = p.CreateEdit() if err != nil { return err } if err := p.CreateJoin(input); err != nil { return err } return p.CreateComment(currentUser, input.Edit.Comment) }) return newEdit, err } func (s *Edit) UpdateStudioEdit(ctx context.Context, id uuid.UUID, input models.StudioEditInput) (*models.Edit, error) { currentUser := auth.GetCurrentUser(ctx) dbEdit, err := s.queries.FindEdit(ctx, id) if err != nil { return nil, err } edit := converter.EditToModelPtr(dbEdit) if err = validateEditUpdate(*edit, currentUser); err != nil { return nil, err } err = s.withTxn(func(tx *queries.Queries) error { p := Studio(ctx, tx, edit) inputArgs := utils.Arguments(ctx).Field("input") if err := p.Edit(input, inputArgs); err != nil { return err } edit, err = p.UpdateEdit() if err != nil { return err } return p.CreateComment(currentUser, input.Edit.Comment) }) return edit, err } func (s *Edit) CreateTagEdit(ctx context.Context, input models.TagEditInput) (*models.Edit, error) { if config.GetRequireTagRole() { if err := auth.ValidateRole(ctx, models.RoleEnumEditTags); err != nil { return nil, err } } UUID, err := uuid.NewV7() if err != nil { return nil, err } // create the edit currentUser := auth.GetCurrentUser(ctx) if err := validateBotEdit(ctx, input.Edit); err != nil { return nil, err } newEdit := models.NewEdit(UUID, currentUser, models.TargetTypeEnumTag, input.Edit) err = s.withTxn(func(tx *queries.Queries) error { p := Tag(ctx, tx, newEdit) inputArgs := utils.Arguments(ctx).Field("input") if err := p.Edit(input, inputArgs); err != nil { return err } newEdit, err = p.CreateEdit() if err != nil { return err } if err := p.CreateJoin(input); err != nil { return err } return p.CreateComment(currentUser, input.Edit.Comment) }) return newEdit, err } func (s *Edit) UpdateTagEdit(ctx context.Context, id uuid.UUID, input models.TagEditInput) (*models.Edit, error) { currentUser := auth.GetCurrentUser(ctx) dbEdit, err := s.queries.FindEdit(ctx, id) if err != nil { return nil, err } edit := converter.EditToModelPtr(dbEdit) if err = validateEditUpdate(*edit, currentUser); err != nil { return nil, err } err = s.withTxn(func(tx *queries.Queries) error { p := Tag(ctx, tx, edit) inputArgs := utils.Arguments(ctx).Field("input") if err := p.Edit(input, inputArgs); err != nil { return err } edit, err = p.UpdateEdit() if err != nil { return err } return p.CreateComment(currentUser, input.Edit.Comment) }) return edit, err } func (s *Edit) CreatePerformerEdit(ctx context.Context, input models.PerformerEditInput) (*models.Edit, error) { UUID, err := uuid.NewV7() if err != nil { return nil, err } // create the edit currentUser := auth.GetCurrentUser(ctx) if err := validateBotEdit(ctx, input.Edit); err != nil { return nil, err } newEdit := models.NewEdit(UUID, currentUser, models.TargetTypeEnumPerformer, input.Edit) err = s.withTxn(func(tx *queries.Queries) error { p := Performer(ctx, tx, newEdit) inputArgs := utils.Arguments(ctx).Field("input") if err := p.Edit(input, inputArgs, false); err != nil { return err } newEdit, err = p.CreateEdit() if err != nil { return err } if err := p.CreateJoin(input); err != nil { return err } if input.Details != nil && input.Details.DraftID != nil { if err := tx.DeleteDraft(ctx, *input.Details.DraftID); err != nil { return err } } return p.CreateComment(currentUser, input.Edit.Comment) }) return newEdit, err } func (s *Edit) UpdatePerformerEdit(ctx context.Context, id uuid.UUID, input models.PerformerEditInput) (*models.Edit, error) { currentUser := auth.GetCurrentUser(ctx) dbEdit, err := s.queries.FindEdit(ctx, id) if err != nil { return nil, err } edit := converter.EditToModelPtr(dbEdit) if err = validateEditUpdate(*edit, currentUser); err != nil { return nil, err } err = s.withTxn(func(tx *queries.Queries) error { p := Performer(ctx, tx, edit) inputArgs := utils.Arguments(ctx).Field("input") if err := p.Edit(input, inputArgs, true); err != nil { return err } edit, err = p.UpdateEdit() if err != nil { return err } return p.CreateComment(currentUser, input.Edit.Comment) }) return edit, err } func (s *Edit) CreateVote(ctx context.Context, input models.EditVoteInput) (*models.Edit, error) { currentUser := auth.GetCurrentUser(ctx) var voteEdit *models.Edit if err := s.withTxn(func(tx *queries.Queries) error { var err error dbEdit, err := tx.FindEdit(ctx, input.ID) if err != nil { return err } voteEdit = converter.EditToModelPtr(dbEdit) if voteEdit.Status != models.VoteStatusEnumPending.String() { return ErrClosedEdit } if err := auth.ValidateOwner(ctx, voteEdit.UserID.UUID); err == nil { return auth.ErrUnauthorized } if err := tx.CreateEditVote(ctx, queries.CreateEditVoteParams{ UserID: currentUser.ID, EditID: voteEdit.ID, Vote: input.Vote.String(), }); err != nil { return err } // Re-fetch the edit to get the updated vote_count from the database trigger dbEdit, err = tx.FindEdit(ctx, input.ID) if err != nil { return err } voteEdit = converter.EditToModelPtr(dbEdit) return nil }); err != nil { return nil, err } result, err := s.ResolveVotingThreshold(ctx, voteEdit) // nolint: exhaustive switch result { case models.VoteStatusEnumAccepted: updatedEdit, applyErr := s.ApplyEdit(ctx, input.ID, false) if applyErr != nil { return nil, applyErr } return updatedEdit, nil case models.VoteStatusEnumRejected: updatedEdit, closeErr := s.CloseEdit(ctx, input.ID, models.VoteStatusEnumRejected) if closeErr != nil { return nil, closeErr } return updatedEdit, nil } return voteEdit, err } func (s *Edit) CreateComment(ctx context.Context, input models.EditCommentInput) (*models.Edit, *models.EditComment, error) { edit, err := s.queries.FindEdit(ctx, input.ID) if err != nil { return nil, nil, err } var comment *models.EditComment err = s.withTxn(func(tx *queries.Queries) error { currentUser := auth.GetCurrentUser(ctx) params, err := converter.CreateEditCommentParams(edit.ID, currentUser.ID, input.Comment) if err != nil { return err } dbComment, err := tx.CreateEditComment(ctx, params) if err != nil { return err } comment = converter.EditCommentToModelPtr(dbComment) return nil }) return converter.EditToModelPtr(edit), comment, err } func (s *Edit) Cancel(ctx context.Context, input models.CancelEditInput) (*models.Edit, error) { e, err := s.queries.FindEdit(ctx, input.ID) if err != nil { return nil, err } if err = auth.ValidateOwner(ctx, e.UserID.UUID); err == nil { return s.CloseEdit(ctx, input.ID, models.VoteStatusEnumCanceled) } else if err = auth.ValidateAdmin(ctx); err == nil { currentUser := auth.GetCurrentUser(ctx) if err := s.queries.CreateEditVote(ctx, queries.CreateEditVoteParams{ UserID: currentUser.ID, EditID: e.ID, Vote: models.VoteTypeEnumImmediateReject.String(), }); err != nil { return nil, err } return s.CloseEdit(ctx, input.ID, models.VoteStatusEnumImmediateRejected) } return nil, err } func (s *Edit) Apply(ctx context.Context, input models.ApplyEditInput) (*models.Edit, error) { edit, err := s.queries.FindEdit(ctx, input.ID) if err != nil { return nil, err } currentUser := auth.GetCurrentUser(ctx) if err := s.queries.CreateEditVote(ctx, queries.CreateEditVoteParams{ UserID: currentUser.ID, EditID: edit.ID, Vote: models.VoteTypeEnumImmediateAccept.String(), }); err != nil { return nil, err } return s.ApplyEdit(ctx, input.ID, true) } func validateBotEdit(ctx context.Context, input *models.EditInput) error { if input.Bot != nil && *input.Bot { if err := auth.ValidateBot(ctx); err != nil { return ErrUnauthorizedBot } } return nil } func validateEditUpdate(edit models.Edit, user *models.User) error { if edit.UserID.UUID != user.ID { return ErrUnauthorizedUpdate } if edit.UpdateCount >= config.GetEditUpdateLimit() { return ErrUpdateLimit } return nil } func (s *Edit) ApplyEdit(ctx context.Context, editID uuid.UUID, immediate bool) (*models.Edit, error) { var updatedEdit *models.Edit dbEdit, err := s.queries.FindEdit(ctx, editID) if err != nil { return nil, err } edit := converter.EditToModelPtr(dbEdit) if err := validateEditPresence(edit); err != nil { return nil, err } if err := validateEditPrerequisites(edit); err != nil { edit.Fail() return nil, err } var operation models.OperationEnum utils.ResolveEnumString(edit.Operation, &operation) var targetType models.TargetTypeEnum utils.ResolveEnumString(edit.TargetType, &targetType) err = s.withTxn(func(tx *queries.Queries) error { var applyer editApplyer switch targetType { case models.TargetTypeEnumTag: applyer = Tag(ctx, tx, edit) case models.TargetTypeEnumPerformer: applyer = Performer(ctx, tx, edit) case models.TargetTypeEnumStudio: applyer = Studio(ctx, tx, edit) case models.TargetTypeEnumScene: applyer = Scene(ctx, tx, edit) } return applyer.apply() }) success := true if err != nil { // Failed apply, so we create a comment with error details success = false commentID, _ := uuid.NewV7() text := "###### Edit application failed: ######\n" if prereqErr := (*validator.ErrEditPrerequisiteFailed)(nil); errors.As(err, &prereqErr) { text = fmt.Sprintf("%sPrerequisite failed: %v", text, err) } else { text = fmt.Sprintf("%sUnknown Error: %v", text, err) } modBotID := getModBot(ctx, s.queries) comment := models.NewEditComment(commentID, modBotID, edit, text) _, err = s.queries.CreateEditComment(ctx, converter.EditCommentToCreateParams(*comment)) if err != nil { return nil, err } } switch { case !success: edit.Fail() case immediate: edit.ImmediateAccept() default: edit.Accept() } dbEdit, err = s.queries.UpdateEdit(ctx, converter.EditToUpdateParams(*edit)) if err != nil { return nil, err } updatedEdit = converter.EditToModelPtr(dbEdit) // TODO: Maybe use cron instead if success { userPromotionThreshold := config.GetVotePromotionThreshold() if userPromotionThreshold != nil && updatedEdit.UserID.Valid { go func() { if err := s.PromoteUserVoteRights(context.Background(), updatedEdit.UserID.UUID, *userPromotionThreshold); err != nil { logger.Errorf("Failed to promote user vote rights: %v", err) } }() } } return updatedEdit, err } func (s *Edit) CloseEdit(ctx context.Context, editID uuid.UUID, status models.VoteStatusEnum) (*models.Edit, error) { var updatedEdit *models.Edit err := s.withTxn(func(tx *queries.Queries) error { dbEdit, err := tx.FindEdit(ctx, editID) if err != nil { return err } edit := converter.EditToModelPtr(dbEdit) if err := validateEditPresence(edit); err != nil { return err } if err := validateEditPrerequisites(edit); err != nil { edit.Fail() return err } switch status { case models.VoteStatusEnumImmediateRejected: edit.ImmediateReject() case models.VoteStatusEnumRejected: edit.Reject() case models.VoteStatusEnumCanceled: edit.Cancel() default: return fmt.Errorf("tried to close with invalid status: %s", status) } dbEdit, err = tx.UpdateEdit(ctx, converter.EditToUpdateParams(*edit)) updatedEdit = converter.EditToModelPtr(dbEdit) return err }) return updatedEdit, err } func (s *Edit) ResolveVotingThreshold(ctx context.Context, edit *models.Edit) (models.VoteStatusEnum, error) { threshold := config.GetVoteApplicationThreshold() if threshold == 0 { return models.VoteStatusEnumPending, nil } // For destructive edits we check if they've been open for a minimum period before applying if edit.IsDestructive() { if time.Since(edit.CreatedAt).Seconds() <= float64(config.GetMinDestructiveVotingPeriod()) { return models.VoteStatusEnumPending, nil } } votes, err := s.queries.GetEditVotes(ctx, edit.ID) if err != nil { return models.VoteStatusEnumPending, err } positive := 0 negative := 0 for _, vote := range votes { if vote.Vote == models.VoteTypeEnumAccept.String() { positive++ } else if vote.Vote == models.VoteTypeEnumReject.String() { negative++ } } if positive >= threshold && negative == 0 { return models.VoteStatusEnumAccepted, nil } else if negative >= threshold && positive == 0 { return models.VoteStatusEnumRejected, nil } return models.VoteStatusEnumPending, nil } func (s *Edit) FindPendingPerformerCreation(ctx context.Context, input models.QueryExistingPerformerInput) ([]models.Edit, error) { dbEdits, err := s.queries.FindPendingPerformerCreation(ctx, queries.FindPendingPerformerCreationParams{ Name: input.Name, Urls: input.Urls, }) var edits []models.Edit for _, edit := range dbEdits { edits = append(edits, converter.EditToModel(edit)) } return edits, err } func (s *Edit) FindPendingSceneCreation(ctx context.Context, input models.QueryExistingSceneInput) ([]models.Edit, error) { var studioID uuid.NullUUID var hashes []string if input.StudioID != nil { studioID = uuid.NullUUID{UUID: *input.StudioID, Valid: true} } for _, fp := range input.Fingerprints { hashes = append(hashes, fp.Hash.Hex()) } rows, err := s.queries.FindPendingSceneCreation(ctx, queries.FindPendingSceneCreationParams{ Title: input.Title, StudioID: studioID, Hashes: hashes, }) return converter.EditsToModels(rows), err } func (s *Edit) CloseCompleted(ctx context.Context) ([]*models.Edit, error) { edits, err := s.queries.FindCompletedEdits(ctx, queries.FindCompletedEditsParams{ VotingPeriod: config.GetVotingPeriod(), MinimumVotes: config.GetVoteApplicationThreshold(), MinimumVotingPeriod: config.GetMinDestructiveVotingPeriod(), }) if err != nil { return nil, err } logger.Debugf("Closing %d completed edits", len(edits)) var closedEdits []*models.Edit for _, edit := range edits { e := converter.EditToModel(edit) voteThreshold := 0 if e.IsDestructive() { // Require at least +1 votes to pass destructive edits voteThreshold = 1 } var err error var closedEdit *models.Edit if e.VoteCount >= voteThreshold { closedEdit, err = s.ApplyEdit(ctx, e.ID, false) } else { closedEdit, err = s.CloseEdit(ctx, e.ID, models.VoteStatusEnumRejected) } if err != nil { return closedEdits, err } closedEdits = append(closedEdits, closedEdit) } return closedEdits, nil } func (s *Edit) PromoteUserVoteRights(ctx context.Context, userID uuid.UUID, threshold int) error { user, err := s.queries.FindUser(ctx, userID) if err != nil { return err } dbRoles, err := s.queries.GetUserRoles(ctx, userID) if err != nil { return err } roles := converter.StringsToRoleEnums(dbRoles) hasVote := false for _, role := range roles { if role == models.RoleEnumReadOnly { return nil } if role.Implies(models.RoleEnumVote) { hasVote = true } } if !hasVote { editCount, err := s.queries.CountUserEditsByStatus(ctx, uuid.NullUUID{UUID: user.ID, Valid: true}) if err != nil { return err } accepted := 0 for _, row := range editCount { if row.Status == models.VoteStatusEnumAccepted.String() || row.Status == models.VoteStatusEnumImmediateAccepted.String() { accepted += int(row.Count) } } if accepted >= threshold { _, err := s.queries.CreateUserRoles(ctx, []queries.CreateUserRolesParams{ { UserID: user.ID, Role: models.RoleEnumVote.String(), }, }) return err } } return nil } // Dataloader methods func (s *Edit) LoadIds(ctx context.Context, ids []uuid.UUID) ([]*models.Edit, []error) { edits, err := s.queries.GetEditsByIds(ctx, ids) if err != nil { return nil, errutil.DuplicateError(err, len(ids)) } result := make([]*models.Edit, len(ids)) editMap := make(map[uuid.UUID]*models.Edit) for _, edit := range edits { editMap[edit.ID] = converter.EditToModelPtr(edit) } for i, id := range ids { result[i] = editMap[id] } return result, make([]error, len(ids)) } func (s *Edit) LoadCommentsByIds(ctx context.Context, ids []uuid.UUID) ([]*models.EditComment, []error) { comments, err := s.queries.GetEditCommentsByIds(ctx, ids) if err != nil { return nil, errutil.DuplicateError(err, len(ids)) } result := make([]*models.EditComment, len(ids)) commentMap := make(map[uuid.UUID]*models.EditComment) for _, comment := range comments { commentMap[comment.ID] = converter.EditCommentToModelPtr(comment) } for i, id := range ids { result[i] = commentMap[id] } return result, make([]error, len(ids)) } ================================================ FILE: internal/service/edit/studio.go ================================================ package edit import ( "context" "errors" "fmt" "reflect" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/converter" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/internal/queries" "github.com/stashapp/stash-box/pkg/utils" ) type StudioEditProcessor struct { mutator } func Studio(ctx context.Context, queries *queries.Queries, edit *models.Edit) *StudioEditProcessor { return &StudioEditProcessor{ mutator{ context: ctx, queries: queries, edit: edit, }, } } func (m *StudioEditProcessor) Edit(input models.StudioEditInput, inputArgs utils.ArgumentsQuery) error { if err := validateStudioEditInput(m.context, m.queries, input); err != nil { return err } var err error switch input.Edit.Operation { case models.OperationEnumModify: err = m.modifyEdit(input, inputArgs) case models.OperationEnumMerge: err = m.mergeEdit(input, inputArgs) case models.OperationEnumDestroy: err = m.destroyEdit(input) case models.OperationEnumCreate: err = m.createEdit(input) } return err } func (m *StudioEditProcessor) modifyEdit(input models.StudioEditInput, inputArgs utils.ArgumentsQuery) error { // get the existing studio studioID := *input.Edit.ID dbStudio, err := m.queries.FindStudio(m.context, studioID) if err != nil { return err } studio := converter.StudioToModel(dbStudio) var entity editEntity = studio if err := validateEditEntity(&entity, studioID, "studio"); err != nil { return err } // perform a diff against the input and the current object detailArgs := inputArgs.Field("details") studioEdit, err := input.Details.StudioEditFromDiff(studio, detailArgs) if err != nil { return err } if err = m.diffRelationships(studioEdit, studioID, input, inputArgs); err != nil { return err } if reflect.DeepEqual(studioEdit.Old, studioEdit.New) { return ErrNoChanges } return m.edit.SetData(studioEdit) } func (m *StudioEditProcessor) diffURLs(studioEdit *models.StudioEditData, studioID uuid.UUID, newURLs []models.URL) error { dbURLs, err := m.queries.GetStudioURLs(m.context, studioID) if err != nil { return err } var urls []models.URL for _, url := range dbURLs { urls = append(urls, models.URL{ URL: url.Url, SiteID: url.SiteID, }) } studioEdit.New.AddedUrls, studioEdit.New.RemovedUrls = urlCompare(newURLs, urls) return nil } func (m *StudioEditProcessor) diffAliases(studioEdit *models.StudioEditData, studioID uuid.UUID, newAliases []string) error { aliases, err := m.queries.GetStudioAliases(m.context, studioID) if err != nil { return err } studioEdit.New.AddedAliases, studioEdit.New.RemovedAliases = utils.SliceCompare(newAliases, aliases) return nil } func (m *StudioEditProcessor) diffImages(studioEdit *models.StudioEditData, studioID uuid.UUID, newImageIds []uuid.UUID) error { images, err := m.queries.FindImagesByStudioID(m.context, studioID) if err != nil { return err } var existingImages []uuid.UUID for _, image := range images { existingImages = append(existingImages, image.ID) } studioEdit.New.AddedImages, studioEdit.New.RemovedImages = utils.SliceCompare(newImageIds, existingImages) return nil } func (m *StudioEditProcessor) mergeEdit(input models.StudioEditInput, inputArgs utils.ArgumentsQuery) error { // get the existing studio if input.Edit.ID == nil { return ErrMergeIDMissing } studioID := *input.Edit.ID dbStudio, err := m.queries.FindStudio(m.context, studioID) if err != nil { return fmt.Errorf("%w: target studio %s: %w", ErrEntityNotFound, studioID.String(), err) } studio := converter.StudioToModel(dbStudio) var mergeSources []uuid.UUID for _, sourceID := range input.Edit.MergeSourceIds { _, err := m.queries.FindStudio(m.context, sourceID) if err != nil { return fmt.Errorf("%w: source studio %s, %w", ErrEntityNotFound, sourceID.String(), err) } if studioID == sourceID { return ErrMergeTargetIsSource } mergeSources = append(mergeSources, sourceID) } if len(mergeSources) < 1 { return ErrNoMergeSources } // perform a diff against the input and the current object detailArgs := inputArgs.Field("details") studioEdit, err := input.Details.StudioEditFromMerge(studio, mergeSources, detailArgs) if err != nil { return err } if err = m.diffRelationships(studioEdit, studioID, input, inputArgs); err != nil { return err } return m.edit.SetData(studioEdit) } func (m *StudioEditProcessor) createEdit(input models.StudioEditInput) error { studioEdit := input.Details.StudioEditFromCreate() studioEdit.New.AddedUrls = input.Details.Urls studioEdit.New.AddedImages = input.Details.ImageIds studioEdit.New.AddedAliases = input.Details.Aliases return m.edit.SetData(studioEdit) } func (m *StudioEditProcessor) destroyEdit(input models.StudioEditInput) error { // Get the existing studio studioID := *input.Edit.ID dbStudio, err := m.queries.FindStudio(m.context, studioID) if err != nil { return err } studio := converter.StudioToModel(dbStudio) var entity editEntity = studio return validateEditEntity(&entity, studioID, "studio") } func (m *StudioEditProcessor) CreateJoin(input models.StudioEditInput) error { if input.Edit.ID != nil { return m.queries.CreateStudioEdit(m.context, queries.CreateStudioEditParams{ EditID: m.edit.ID, StudioID: *input.Edit.ID, }) } return nil } func (m *StudioEditProcessor) apply() error { operation := m.operation() isCreate := operation == models.OperationEnumCreate var studio *models.Studio if !isCreate { res, err := m.queries.GetEditTargetID(m.context, m.edit.ID) if err != nil { return err } dbStudio, err := m.queries.FindStudio(m.context, res.ID) if err != nil { return fmt.Errorf("%w: studio %s: %w", ErrEntityNotFound, res.ID.String(), err) } studio = converter.StudioToModelPtr(dbStudio) } data, err := m.edit.GetStudioData() if err != nil { return err } switch operation { case models.OperationEnumCreate: studioID, err := uuid.NewV7() if err != nil { return err } newStudio := models.Studio{ ID: studioID, } if data.New.Name == nil { return errors.New("missing studio name") } newStudio.CopyFromStudioEdit(*data.New, &models.StudioEdit{}) _, err = m.queries.CreateStudio(m.context, converter.StudioToCreateParams(newStudio)) if err != nil { return err } if len(data.New.AddedUrls) > 0 { var urls []queries.CreateStudioURLsParams for _, url := range data.New.AddedUrls { urls = append(urls, queries.CreateStudioURLsParams{ StudioID: studioID, Url: url.URL, SiteID: url.SiteID, }) } _, err = m.queries.CreateStudioURLs(m.context, urls) if err != nil { return err } } if len(data.New.AddedImages) > 0 { var params []queries.CreateStudioImagesParams for _, image := range data.New.AddedImages { params = append(params, queries.CreateStudioImagesParams{ StudioID: studioID, ImageID: image, }) } _, err := m.queries.CreateStudioImages(m.context, params) if err != nil { return err } } if len(data.New.AddedAliases) > 0 { var params []queries.CreateStudioAliasesParams for _, alias := range data.New.AddedAliases { params = append(params, queries.CreateStudioAliasesParams{ StudioID: studioID, Alias: alias, }) } _, err := m.queries.CreateStudioAliases(m.context, params) if err != nil { return err } } return m.queries.CreateStudioEdit(m.context, queries.CreateStudioEditParams{ EditID: m.edit.ID, StudioID: studioID, }) case models.OperationEnumDestroy: _, err := m.queries.SoftDeleteStudio(m.context, studio.ID) if err != nil { return err } if err := m.queries.DeleteSceneStudios(m.context, uuid.NullUUID{UUID: studio.ID, Valid: true}); err != nil { return err } if err = m.queries.DeleteStudioFavorites(m.context, studio.ID); err != nil { return err } if err = m.queries.DeleteStudioAliases(m.context, studio.ID); err != nil { return err } return nil case models.OperationEnumModify: return m.applyModifyEdit(studio, data) case models.OperationEnumMerge: err := m.applyModifyEdit(studio, data) if err != nil { return err } for _, sourceID := range data.MergeSources { if err := m.mergeInto(sourceID, studio.ID); err != nil { return err } } return nil default: return errors.New("Unsupported operation: " + operation.String()) } } func (m *StudioEditProcessor) applyModifyEdit(studio *models.Studio, data *models.StudioEditData) error { if err := studio.ValidateModifyEdit(*data); err != nil { return err } studio.CopyFromStudioEdit(*data.New, data.Old) updatedDbStudio, err := m.queries.UpdateStudio(m.context, converter.StudioToUpdateParams(*studio)) if err != nil { return err } updatedStudio := converter.StudioToModelPtr(updatedDbStudio) if err := m.updateURLsFromEdit(updatedStudio, data); err != nil { return err } if err := m.updateImagesFromEdit(updatedStudio, data); err != nil { return err } if err := m.updateAliasesFromEdit(updatedStudio, data); err != nil { return err } return err } func (m *StudioEditProcessor) updateURLsFromEdit(studio *models.Studio, data *models.StudioEditData) error { urls, err := m.queries.GetMergedURLsForEdit(m.context, m.edit.ID) if err != nil { return err } if err := m.queries.DeleteStudioURLs(m.context, studio.ID); err != nil { return err } var urlsParams []queries.CreateStudioURLsParams for _, url := range urls { urlsParams = append(urlsParams, queries.CreateStudioURLsParams{ StudioID: studio.ID, Url: url.Url, SiteID: url.SiteID, }) } _, err = m.queries.CreateStudioURLs(m.context, urlsParams) return err } func (m StudioEditProcessor) updateImagesFromEdit(studio *models.Studio, data *models.StudioEditData) error { dbImages, err := m.queries.GetImagesForEdit(m.context, m.edit.ID) if err != nil { return err } if err := m.queries.DeleteStudioImages(m.context, studio.ID); err != nil { return err } var images []queries.CreateStudioImagesParams for _, image := range dbImages { images = append(images, queries.CreateStudioImagesParams{ StudioID: studio.ID, ImageID: image.ID, }) } _, err = m.queries.CreateStudioImages(m.context, images) return err } func (m *StudioEditProcessor) mergeInto(sourceID uuid.UUID, targetID uuid.UUID) error { studio, err := m.queries.FindStudio(m.context, sourceID) if err != nil { return fmt.Errorf("merge source studio not found, %v: %w"+sourceID.String(), err) } if studio.Deleted { return fmt.Errorf("merge source studio is deleted, %v: %w"+sourceID.String(), err) } _, err = m.queries.SoftDeleteStudio(m.context, studio.ID) if err != nil { return err } if err = m.queries.UpdateStudioRedirects(m.context, queries.UpdateStudioRedirectsParams{ OldTargetID: sourceID, NewTargetID: targetID, }); err != nil { return err } if err = m.queries.UpdateSceneStudios(m.context, queries.UpdateSceneStudiosParams{ SourceID: uuid.NullUUID{UUID: sourceID, Valid: true}, TargetID: uuid.NullUUID{UUID: targetID, Valid: true}, }); err != nil { return err } if err = m.queries.ReassignStudioFavorites(m.context, queries.ReassignStudioFavoritesParams{ OldStudioID: sourceID, NewStudioID: targetID, }); err != nil { return err } return m.queries.CreateStudioRedirect(m.context, queries.CreateStudioRedirectParams{ SourceID: sourceID, TargetID: targetID, }) } func (m *StudioEditProcessor) diffRelationships(studioEdit *models.StudioEditData, studioID uuid.UUID, input models.StudioEditInput, inputArgs utils.ArgumentsQuery) error { if input.Details.Urls != nil || inputArgs.Field("urls").IsNull() { if err := m.diffURLs(studioEdit, studioID, input.Details.Urls); err != nil { return err } } if input.Details.ImageIds != nil || inputArgs.Field("image_ids").IsNull() { if err := m.diffImages(studioEdit, studioID, input.Details.ImageIds); err != nil { return err } } if input.Details.Aliases != nil || inputArgs.Field("aliases").IsNull() { if err := m.diffAliases(studioEdit, studioID, input.Details.Aliases); err != nil { return err } } return nil } func (m *StudioEditProcessor) updateAliasesFromEdit(studio *models.Studio, data *models.StudioEditData) error { aliases, err := m.queries.GetMergedStudioAliasesForEdit(m.context, m.edit.ID) if err != nil { return err } if err := m.queries.DeleteStudioAliases(m.context, studio.ID); err != nil { return err } var params []queries.CreateStudioAliasesParams for _, alias := range aliases { params = append(params, queries.CreateStudioAliasesParams{ StudioID: studio.ID, Alias: alias, }) } _, err = m.queries.CreateStudioAliases(m.context, params) return err } ================================================ FILE: internal/service/edit/tag.go ================================================ package edit import ( "context" "errors" "fmt" "reflect" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/converter" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/internal/queries" "github.com/stashapp/stash-box/pkg/utils" ) type TagEditProcessor struct { mutator } func Tag(ctx context.Context, queries *queries.Queries, edit *models.Edit) *TagEditProcessor { return &TagEditProcessor{ mutator{ context: ctx, queries: queries, edit: edit, }, } } func (m *TagEditProcessor) Edit(input models.TagEditInput, inputArgs utils.ArgumentsQuery) error { var err error switch input.Edit.Operation { case models.OperationEnumModify: err = m.modifyEdit(input, inputArgs) case models.OperationEnumMerge: err = m.mergeEdit(input, inputArgs) case models.OperationEnumDestroy: err = m.destroyEdit(input) case models.OperationEnumCreate: err = m.createEdit(input, inputArgs) } return err } func (m *TagEditProcessor) modifyEdit(input models.TagEditInput, inputArgs utils.ArgumentsQuery) error { // get the existing tag tagID := *input.Edit.ID dbTag, err := m.queries.FindTag(m.context, tagID) if err != nil { return err } tag := converter.TagToModel(dbTag) var entity editEntity = tag if err := validateEditEntity(&entity, tagID, "tag"); err != nil { return err } // perform a diff against the input and the current object detailArgs := inputArgs.Field("details") tagEdit := input.Details.TagEditFromDiff(tag, detailArgs) aliases, err := m.queries.GetTagAliases(m.context, tagID) if err != nil { return err } if input.Details.Aliases != nil || inputArgs.Field("aliases").IsNull() { tagEdit.New.AddedAliases, tagEdit.New.RemovedAliases = utils.SliceCompare(input.Details.Aliases, aliases) } if reflect.DeepEqual(tagEdit.Old, tagEdit.New) { return ErrNoChanges } return m.edit.SetData(tagEdit) } func (m *TagEditProcessor) mergeEdit(input models.TagEditInput, inputArgs utils.ArgumentsQuery) error { // get the existing tag if input.Edit.ID == nil { return ErrMergeIDMissing } tagID := *input.Edit.ID dbTag, err := m.queries.FindTag(m.context, tagID) if err != nil { return fmt.Errorf("%w: target tag %s: %w", ErrEntityNotFound, tagID.String(), err) } tag := converter.TagToModel(dbTag) var mergeSources []uuid.UUID for _, sourceID := range input.Edit.MergeSourceIds { if tagID == sourceID { return ErrMergeTargetIsSource } _, err := m.queries.FindTag(m.context, tagID) if err != nil { return fmt.Errorf("%w: source tag %s: %w", ErrEntityNotFound, sourceID.String(), err) } mergeSources = append(mergeSources, sourceID) } if len(mergeSources) < 1 { return ErrNoMergeSources } // perform a diff against the input and the current object detailArgs := inputArgs.Field("details") tagEdit := input.Details.TagEditFromMerge(tag, mergeSources, detailArgs) aliases, err := m.queries.GetTagAliases(m.context, tagID) if err != nil { return err } tagEdit.New.AddedAliases, tagEdit.New.RemovedAliases = utils.SliceCompare(input.Details.Aliases, aliases) return m.edit.SetData(tagEdit) } func (m *TagEditProcessor) createEdit(input models.TagEditInput, inputArgs utils.ArgumentsQuery) error { tagEdit := input.Details.TagEditFromCreate(inputArgs) tagEdit.New.AddedAliases = input.Details.Aliases return m.edit.SetData(tagEdit) } func (m *TagEditProcessor) destroyEdit(input models.TagEditInput) error { // Get the existing tag tagID := *input.Edit.ID dbTag, err := m.queries.FindTag(m.context, tagID) if err != nil { return err } tag := converter.TagToModel(dbTag) var entity editEntity = tag return validateEditEntity(&entity, tagID, "tag") } func (m *TagEditProcessor) CreateJoin(input models.TagEditInput) error { if input.Edit.ID != nil { return m.queries.CreateTagEdit(m.context, queries.CreateTagEditParams{ EditID: m.edit.ID, TagID: *input.Edit.ID, }) } return nil } func (m *TagEditProcessor) updateAliasesFromEdit(tag *models.Tag, data *models.TagEditData) error { aliases, err := m.queries.GetMergedTagAliasesForEdit(m.context, m.edit.ID) if err != nil { return err } if err := m.queries.DeleteTagAliases(m.context, tag.ID); err != nil { return err } var params []queries.CreateTagAliasesParams for _, alias := range aliases { params = append(params, queries.CreateTagAliasesParams{ TagID: tag.ID, Alias: alias, }) } _, err = m.queries.CreateTagAliases(m.context, params) return err } func (m *TagEditProcessor) apply() error { operation := m.operation() isCreate := operation == models.OperationEnumCreate var tag *models.Tag if !isCreate { res, err := m.queries.GetEditTargetID(m.context, m.edit.ID) if err != nil { return err } dbTag, err := m.queries.FindTag(m.context, res.ID) if err != nil { return fmt.Errorf("%w: tag %s", ErrEntityNotFound, res.ID.String()) } tag = converter.TagToModelPtr(dbTag) } data, err := m.edit.GetTagData() if err != nil { return err } switch operation { case models.OperationEnumCreate: UUID, err := uuid.NewV7() if err != nil { return err } newTag := models.Tag{ ID: UUID, } if data.New.Name == nil { return errors.New("missing tag name") } newTag.CopyFromTagEdit(*data.New, &models.TagEdit{}) _, err = m.queries.CreateTag(m.context, converter.TagToCreateParams(newTag)) if err != nil { return err } if len(data.New.AddedAliases) > 0 { var params []queries.CreateTagAliasesParams for _, alias := range data.New.AddedAliases { params = append(params, queries.CreateTagAliasesParams{ TagID: newTag.ID, Alias: alias, }) } _, err := m.queries.CreateTagAliases(m.context, params) if err != nil { return err } } return m.queries.CreateTagEdit(m.context, queries.CreateTagEditParams{ EditID: m.edit.ID, TagID: newTag.ID, }) case models.OperationEnumDestroy: _, err := m.queries.SoftDeleteTag(m.context, tag.ID) if err != nil { return err } // TODO: Not cascading? err = m.queries.DeleteSceneTagsByTag(m.context, tag.ID) if err != nil { return err } if err = m.queries.DeleteTagAliases(m.context, tag.ID); err != nil { return err } case models.OperationEnumModify: if err := tag.ValidateModifyEdit(*data); err != nil { return err } tag.CopyFromTagEdit(*data.New, data.Old) _, err = m.queries.UpdateTag(m.context, converter.TagToUpdateParams(*tag)) if err != nil { return err } return m.updateAliasesFromEdit(tag, data) case models.OperationEnumMerge: if err := tag.ValidateModifyEdit(*data); err != nil { return err } tag.CopyFromTagEdit(*data.New, data.Old) _, err = m.queries.UpdateTag(m.context, converter.TagToUpdateParams(*tag)) if err != nil { return err } for _, sourceID := range data.MergeSources { if err := m.mergeInto(sourceID, tag.ID); err != nil { return err } } return m.updateAliasesFromEdit(tag, data) default: return errors.New("Unsupported operation: " + operation.String()) } return nil } func (m *TagEditProcessor) mergeInto(sourceID uuid.UUID, targetID uuid.UUID) error { tag, err := m.queries.FindTag(m.context, sourceID) if err != nil { return fmt.Errorf("merge source tag not found, %v: %v"+sourceID.String(), err) } if tag.Deleted { return errors.New("merge source tag is deleted, %v" + sourceID.String()) } _, err = m.queries.SoftDeleteTag(m.context, sourceID) if err != nil { return err } if err = m.queries.UpdateTagRedirects(m.context, queries.UpdateTagRedirectsParams{ OldTargetID: sourceID, NewTargetID: targetID, }); err != nil { return err } if err = m.queries.UpdateSceneTagsForMerge(m.context, queries.UpdateSceneTagsForMergeParams{ OldTagID: sourceID, NewTagID: targetID, }); err != nil { return err } // Delete any remaining old tags (these are scenes that already had the target tag) if err = m.queries.DeleteSceneTagsByTag(m.context, sourceID); err != nil { return err } return m.queries.CreateTagRedirect(m.context, queries.CreateTagRedirectParams{ SourceID: sourceID, TargetID: targetID, }) } ================================================ FILE: internal/service/edit/validate.go ================================================ package edit import ( "context" "encoding/json" "errors" "fmt" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/internal/queries" "github.com/stashapp/stash-box/pkg/utils" ) var ErrEditAlreadyApplied = errors.New("edit already applied") var ErrInvalidVoteStatus = errors.New("invalid vote status") var ErrEditNotFound = errors.New("edit not found") var ErrEntityNotFound = errors.New("entity not found") var ErrEntityDeleted = errors.New("entity is deleted") var ErrInvalidDraft = errors.New("invalid draft id") var ErrInvalidImage = errors.New("invalid image id") var ErrInvalidStudio = errors.New("invalid studio id") var ErrInvalidPerformer = errors.New("invalid performer id") var ErrInvalidTag = errors.New("invalid tag id") var ErrInvalidSite = errors.New("invalid url site id") type editEntity interface { IsDeleted() bool } func validateEditEntity(entity *editEntity, id uuid.UUID, typeName string) error { if entity == nil { return fmt.Errorf("%w: %s %s", ErrEntityNotFound, typeName, id.String()) } if (*entity).IsDeleted() { return fmt.Errorf("%w: %s %s", ErrEntityDeleted, typeName, id.String()) } return nil } func validateEditPresence(edit *models.Edit) error { if edit == nil { return ErrEditNotFound } if edit.Applied { return ErrEditAlreadyApplied } return nil } func validateEditPrerequisites(edit *models.Edit) error { var status models.VoteStatusEnum utils.ResolveEnumString(edit.Status, &status) if status != models.VoteStatusEnumPending { return fmt.Errorf("%w: %s", ErrInvalidVoteStatus, edit.Status) } return nil } func validateSceneEditInput(ctx context.Context, queries *queries.Queries, input models.SceneEditInput, edit *models.Edit, update bool) error { if input.Details == nil { return nil } if input.Details.DraftID != nil { if err := validateDraftID(ctx, queries, *input.Details.DraftID, edit.ID, update); err != nil { return err } } if input.Details.StudioID != nil { _, err := queries.FindStudio(ctx, *input.Details.StudioID) if err != nil { return fmt.Errorf("%w: %s", ErrInvalidStudio, *input.Details.StudioID) } } if len(input.Details.ImageIds) > 0 { images, err := queries.FindImagesByIds(ctx, input.Details.ImageIds) if err != nil || len(images) < len(input.Details.ImageIds) { return fmt.Errorf("%w: %w", ErrInvalidImage, err) } } if len(input.Details.TagIds) > 0 { tags, err := queries.FindTagsByIds(ctx, input.Details.TagIds) if err != nil || len(tags) < len(input.Details.TagIds) { return fmt.Errorf("%w: %w", ErrInvalidTag, err) } } if len(input.Details.Performers) > 0 { var ids []uuid.UUID for _, appearance := range input.Details.Performers { ids = append(ids, appearance.PerformerID) } performers, err := queries.FindPerformersByIds(ctx, ids) if err != nil || len(performers) < len(ids) { return fmt.Errorf("%w: %w", ErrInvalidPerformer, err) } } return validateURLs(ctx, queries, input.Details.Urls) } func validatePerformerEditInput(ctx context.Context, queries *queries.Queries, input models.PerformerEditInput, edit *models.Edit, update bool) error { if input.Details == nil { return nil } if input.Details.DraftID != nil { if err := validateDraftID(ctx, queries, *input.Details.DraftID, edit.ID, update); err != nil { return err } } if len(input.Details.ImageIds) > 0 { images, err := queries.FindImagesByIds(ctx, input.Details.ImageIds) if err != nil || len(images) < len(input.Details.ImageIds) { return fmt.Errorf("%w: %w", ErrInvalidImage, err) } } return validateURLs(ctx, queries, input.Details.Urls) } func validateDraftID(ctx context.Context, queries *queries.Queries, draftID uuid.UUID, editID uuid.UUID, update bool) error { if !update { _, err := queries.FindDraft(ctx, draftID) if err != nil { return fmt.Errorf("%w: %s", ErrInvalidDraft, draftID) } } else { edit, err := queries.FindEdit(ctx, editID) if err != nil { return err } type Data struct { New struct { DraftID *uuid.UUID `json:"draft_id"` } `json:"new_data"` } var data Data err = json.Unmarshal(edit.Data, &data) if err != nil { return err } if data.New.DraftID == nil || *data.New.DraftID != draftID { return fmt.Errorf("%w: %s", ErrInvalidDraft, draftID) } } return nil } func validateStudioEditInput(ctx context.Context, queries *queries.Queries, input models.StudioEditInput) error { if input.Details == nil { return nil } if input.Details.ParentID != nil { _, err := queries.FindStudio(ctx, *input.Details.ParentID) if err != nil { return fmt.Errorf("%w: %s", ErrInvalidStudio, *input.Details.ParentID) } } if len(input.Details.ImageIds) > 0 { images, err := queries.FindImagesByIds(ctx, input.Details.ImageIds) if err != nil || len(images) < len(input.Details.ImageIds) { return fmt.Errorf("%w: %w", ErrInvalidImage, err) } } return validateURLs(ctx, queries, input.Details.Urls) } func validateURLs(ctx context.Context, queries *queries.Queries, urls []models.URL) error { if len(urls) == 0 { return nil } var ids []uuid.UUID for _, url := range urls { ids = append(ids, url.SiteID) } sites, err := queries.FindSitesByIds(ctx, ids) if err != nil { return fmt.Errorf("%w: %w", ErrInvalidSite, err) } siteMap := make(map[uuid.UUID]bool, len(sites)) for _, site := range sites { siteMap[site.ID] = true } for _, id := range ids { if !siteMap[id] { return fmt.Errorf("%w", ErrInvalidSite) } } return nil } ================================================ FILE: internal/service/errutil/errors.go ================================================ package errutil import ( "errors" "github.com/jackc/pgx/v5" ) // IgnoreNotFound returns nil if err is pgx.ErrNoRows, otherwise returns err. // This is useful for queries where "not found" should be treated as a non-error case. func IgnoreNotFound(err error) error { if errors.Is(err, pgx.ErrNoRows) { return nil } return err } // DuplicateError creates a slice of the same error repeated size times. // This is useful for dataloader methods that need to return one error per requested ID. func DuplicateError(err error, size int) []error { errs := make([]error, size) for i := range errs { errs[i] = err } return errs } ================================================ FILE: internal/service/factory.go ================================================ // Package service provides a centralized service factory for database operations. // // Usage: // // // Initialize the factory with a database pool // pool, err := pgxpool.New(context.Background(), databaseURL) // if err != nil { // log.Fatal(err) // } // factory := service.NewFactory(pool) // // // Each service call creates a fresh querier instance // tagService := factory.Tag() // tag, err := tagService.FindByID(ctx, tagID) // // userService := factory.User() // user, err := userService.FindByID(ctx, userID) package service import ( "github.com/jackc/pgx/v5/pgxpool" "github.com/stashapp/stash-box/internal/email" "github.com/stashapp/stash-box/internal/queries" "github.com/stashapp/stash-box/internal/service/draft" "github.com/stashapp/stash-box/internal/service/edit" "github.com/stashapp/stash-box/internal/service/image" "github.com/stashapp/stash-box/internal/service/invite" "github.com/stashapp/stash-box/internal/service/mod_audit" "github.com/stashapp/stash-box/internal/service/notification" "github.com/stashapp/stash-box/internal/service/performer" "github.com/stashapp/stash-box/internal/service/scene" "github.com/stashapp/stash-box/internal/service/site" "github.com/stashapp/stash-box/internal/service/studio" "github.com/stashapp/stash-box/internal/service/tag" "github.com/stashapp/stash-box/internal/service/user" "github.com/stashapp/stash-box/internal/service/usertoken" ) // Factory provides access to all services with centralized database connection management type Factory struct { db *pgxpool.Pool withTxn queries.WithTxnFunc emailMgr *email.Manager } // NewFactory creates a new service factory with the given database pool and email manager func NewFactory(pool *pgxpool.Pool, emailMgr *email.Manager) *Factory { return &Factory{ db: pool, withTxn: createWithTxnFunc(pool), emailMgr: emailMgr, } } // Tag returns a TagService instance func (f *Factory) Tag() *tag.Tag { return tag.NewTag(queries.New(f.db), f.withTxn) } // Performer returns a PerformerService instance func (f *Factory) Performer() *performer.Performer { return performer.NewPerformer(queries.New(f.db), f.withTxn) } // Scene returns a SceneService instance func (f *Factory) Scene() *scene.Scene { return scene.NewScene(queries.New(f.db), f.withTxn) } // Studio returns a StudioService instance func (f *Factory) Studio() *studio.Studio { return studio.NewStudio(queries.New(f.db), f.withTxn) } // User returns a UserService instance func (f *Factory) User() *user.User { return user.NewUser(queries.New(f.db), f.withTxn, f.emailMgr) } // UserToken returns a UserTokenService instance func (f *Factory) UserToken() *usertoken.UserToken { return usertoken.NewUserToken(queries.New(f.db), f.withTxn) } // Site returns a SiteService instance func (f *Factory) Site() *site.Site { return site.NewSite(queries.New(f.db), f.withTxn) } // Edit returns an EditService instance func (f *Factory) Edit() *edit.Edit { return edit.NewEdit(queries.New(f.db), f.withTxn) } // Image returns an ImageService instance func (f *Factory) Image() *image.Image { return image.NewImage(queries.New(f.db), f.withTxn) } // Draft returns a DraftService instance func (f *Factory) Draft() *draft.Draft { return draft.NewDraft(queries.New(f.db), f.withTxn) } // Notification returns a NotificationService instance func (f *Factory) Notification() *notification.Notification { return notification.NewNotification(queries.New(f.db), f.withTxn) } func (f *Factory) Invite() *invite.Invite { return invite.NewInvite(queries.New(f.db), f.withTxn) } // ModAudit returns a ModAuditService instance func (f *Factory) ModAudit() *mod_audit.ModAuditService { return mod_audit.NewModAuditService(queries.New(f.db)) } ================================================ FILE: internal/service/image/service.go ================================================ package image import ( "bytes" "context" "database/sql" "errors" "io" "strings" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/converter" "github.com/stashapp/stash-box/internal/image/cache" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/internal/queries" "github.com/stashapp/stash-box/internal/service/errutil" "github.com/stashapp/stash-box/internal/storage" ) type Image struct { queries *queries.Queries withTxn queries.WithTxnFunc } func NewImage(queries *queries.Queries, withTxn queries.WithTxnFunc) *Image { return &Image{ queries: queries, withTxn: withTxn, } } // WithTxn executes a function within a transaction func (s *Image) WithTxn(fn func(*queries.Queries) error) error { return s.withTxn(fn) } func (s *Image) Create(ctx context.Context, input models.ImageCreateInput) (*models.Image, error) { UUID, err := uuid.NewV4() if err != nil { return nil, err } // Generate uuid that does not start with AD to prevent adblock issues for strings.HasPrefix(UUID.String(), "ad") { UUID, err = uuid.NewV7() if err != nil { return nil, err } } newImage := models.Image{ ID: UUID, } // set RemoteURL from URL if input.URL != nil { newImage.RemoteURL = input.URL } // handle image upload if input.File != nil { if input.File.Size > int64(10*1024*1024) { return nil, errors.New("file too big") } file := make([]byte, input.File.Size) if _, err := input.File.File.Read(file); err != nil { return nil, err } fileReader := bytes.NewReader(file) checksum, err := calculateChecksum(fileReader) if err != nil { return nil, err } // check if image already exists with this checksum existing, err := s.FindByChecksum(ctx, checksum) if err != nil { return nil, err } // if image already exists, just return it if existing != nil { return existing, nil } // set the checksum in the new image newImage.Checksum = checksum if _, err = fileReader.Seek(0, 0); err != nil { return nil, err } if err := populateImageDimensions(fileReader, &newImage); err != nil { return nil, err } if err := storage.Image().WriteFile(file, &newImage); err != nil { return nil, err } } else if input.URL == nil { return nil, errors.New("missing URL or file") } params := queries.CreateImageParams{ ID: newImage.ID, Checksum: newImage.Checksum, Width: newImage.Width, Height: newImage.Height, Url: newImage.RemoteURL, } dbImage, err := s.queries.CreateImage(ctx, params) if err != nil { return nil, err } return converter.ImageToModelPtr(dbImage), nil } func (s *Image) Destroy(ctx context.Context, id uuid.UUID) error { image, err := s.Find(ctx, id) if err != nil { return err } if err := s.queries.DeleteImage(ctx, id); err != nil { return err } // delete the file. Suppress any error _ = storage.Image().DestroyFile(image) // Clear image from cache cacheManager := cache.GetCacheManager() if cacheManager != nil { _ = cacheManager.Delete(id) } return nil } func (s *Image) Find(ctx context.Context, id uuid.UUID) (*models.Image, error) { dbImage, err := s.queries.FindImage(ctx, id) if err != nil { if errors.Is(err, sql.ErrNoRows) { return nil, nil } return nil, err } return converter.ImageToModelPtr(dbImage), nil } func (s *Image) FindBySceneID(ctx context.Context, sceneID uuid.UUID) ([]models.Image, error) { dbImages, err := s.queries.FindImagesBySceneID(ctx, sceneID) if err != nil { return nil, err } return converter.ImagesToModels(dbImages), nil } func (s *Image) FindByChecksum(ctx context.Context, checksum string) (*models.Image, error) { dbImage, err := s.queries.FindImageByChecksum(ctx, checksum) if err != nil { if errors.Is(err, sql.ErrNoRows) { return nil, nil } return nil, err } return converter.ImageToModelPtr(dbImage), nil } func (s *Image) DestroyUnusedImages(ctx context.Context) error { unused, err := s.FindUnused(ctx) if err != nil { return err } cacheManager := cache.GetCacheManager() for len(unused) > 0 { for _, i := range unused { err = s.Destroy(ctx, i.ID) if err != nil { return err } // Clear image from cache if cacheManager != nil { _ = cacheManager.Delete(i.ID) } } unused, err = s.FindUnused(ctx) if err != nil { return err } } return nil } func (s *Image) DestroyUnusedImage(ctx context.Context, imageID uuid.UUID) error { unused, err := s.IsUnused(ctx, imageID) if err != nil { return err } if unused { err = s.Destroy(ctx, imageID) if err != nil { return err } } return nil } func (s *Image) FindUnused(ctx context.Context) ([]models.Image, error) { dbImages, err := s.queries.FindUnusedImages(ctx) if err != nil { return nil, err } return converter.ImagesToModels(dbImages), nil } func (s *Image) IsUnused(ctx context.Context, imageID uuid.UUID) (bool, error) { return s.queries.IsImageUnused(ctx, imageID) } // Dataloader for images by ids func (s *Image) LoadIds(ctx context.Context, ids []uuid.UUID) ([]*models.Image, []error) { dbImages, err := s.queries.FindImagesByIds(ctx, ids) if err != nil { return nil, errutil.DuplicateError(err, len(ids)) } m := make(map[uuid.UUID]*models.Image) for _, dbImage := range dbImages { m[dbImage.ID] = converter.ImageToModelPtr(dbImage) } result := make([]*models.Image, len(ids)) for i, id := range ids { result[i] = m[id] } return result, nil } // Dataloder for images for scenes func (s *Image) LoadBySceneIds(ctx context.Context, ids []uuid.UUID) ([][]uuid.UUID, []error) { sceneImages, err := s.queries.FindImageIdsBySceneIds(ctx, ids) if err != nil { return nil, errutil.DuplicateError(err, len(ids)) } m := make(map[uuid.UUID][]uuid.UUID) for _, sceneImage := range sceneImages { m[sceneImage.SceneID] = append(m[sceneImage.SceneID], sceneImage.ImageID) } result := make([][]uuid.UUID, len(ids)) for i, id := range ids { result[i] = m[id] } return result, nil } // Dataloder for images for performers func (s *Image) LoadByPerformerIds(ctx context.Context, ids []uuid.UUID) ([][]uuid.UUID, []error) { performerImages, err := s.queries.FindImageIdsByPerformerIds(ctx, ids) if err != nil { return nil, errutil.DuplicateError(err, len(ids)) } m := make(map[uuid.UUID][]uuid.UUID) for _, performerImage := range performerImages { m[performerImage.PerformerID] = append(m[performerImage.PerformerID], performerImage.ImageID) } result := make([][]uuid.UUID, len(ids)) for i, id := range ids { result[i] = m[id] } return result, nil } func (s *Image) FindByPerformerID(ctx context.Context, performerID uuid.UUID) ([]models.Image, error) { dbImages, err := s.queries.GetPerformerImages(ctx, performerID) if err != nil { return nil, err } return converter.ImagesToModels(dbImages), nil } func (s *Image) FindByStudioID(ctx context.Context, studioID uuid.UUID) ([]models.Image, error) { dbImages, err := s.queries.FindImagesByStudioID(ctx, studioID) if err != nil { return nil, err } return converter.ImagesToModels(dbImages), nil } func (s *Image) LoadByStudioIds(ctx context.Context, ids []uuid.UUID) ([][]uuid.UUID, []error) { studioImages, err := s.queries.FindImageIdsByStudioIds(ctx, ids) if err != nil { return nil, errutil.DuplicateError(err, len(ids)) } m := make(map[uuid.UUID][]uuid.UUID) for _, studioImage := range studioImages { m[studioImage.StudioID] = append(m[studioImage.StudioID], studioImage.ImageID) } result := make([][]uuid.UUID, len(ids)) for i, id := range ids { result[i] = m[id] } return result, nil } func (s *Image) Read(image models.Image) (io.ReadCloser, int64, error) { return storage.Image().ReadFile(image) } ================================================ FILE: internal/service/image/utils.go ================================================ package image import ( "bytes" "crypto/md5" "encoding/hex" "errors" "fmt" "image" _ "image/gif" "image/jpeg" "image/png" "io" _ "golang.org/x/image/webp" "github.com/disintegration/imaging" issvg "github.com/h2non/go-is-svg" "github.com/stashapp/stash-box/internal/config" "github.com/stashapp/stash-box/internal/models" ) var ErrImageZeroSize = errors.New("image has 0px dimension") func populateImageDimensions(imgReader *bytes.Reader, dest *models.Image) error { img, format, err := image.Decode(imgReader) if err != nil { // SVG is not an image so we have to manually check if the image is SVG if _, readerErr := imgReader.Seek(0, 0); readerErr != nil { return readerErr } buf := new(bytes.Buffer) if _, bufErr := buf.ReadFrom(imgReader); bufErr != nil { return bufErr } if issvg.IsSVG(buf.Bytes()) { dest.Width = -1 dest.Height = -1 return nil } return err } if format != "jpeg" && format != "webp" && format != "png" { return fmt.Errorf("unsupported image format: %s", format) } dest.Width = img.Bounds().Max.X dest.Height = img.Bounds().Max.Y if dest.Width == 0 || dest.Height == 0 { return ErrImageZeroSize } return nil } //nolint:unused func resizeImage(srcReader io.Reader, maxDimension int64) ([]byte, error) { var resizedImage image.Image srcImage, format, err := image.Decode(srcReader) if err != nil { return nil, err } // if height is longer then resize by height instead of width if dim := srcImage.Bounds().Max; dim.Y > dim.X { resizedImage = imaging.Resize(srcImage, 0, int(maxDimension), imaging.MitchellNetravali) } else { resizedImage = imaging.Resize(srcImage, int(maxDimension), 0, imaging.MitchellNetravali) } buf := new(bytes.Buffer) if format == "png" { err = png.Encode(buf, resizedImage) if err != nil { return nil, err } } else { options := jpeg.Options{ Quality: config.GetImageJpegQuality(), } err = jpeg.Encode(buf, resizedImage, &options) if err != nil { return nil, err } } return buf.Bytes(), nil } func calculateChecksum(file io.Reader) (string, error) { hasher := md5.New() if _, err := io.Copy(hasher, file); err != nil { return "", err } checksum := hex.EncodeToString(hasher.Sum(nil)) return checksum, nil } ================================================ FILE: internal/service/interface.go ================================================ package service import ( "context" "github.com/jackc/pgx/v5/pgxpool" "github.com/stashapp/stash-box/internal/queries" ) // createWithTxnFunc creates a WithTxn function using the provided pgx pool func createWithTxnFunc(pool *pgxpool.Pool) queries.WithTxnFunc { return func(fn func(*queries.Queries) error) (err error) { ctx := context.Background() // Start a transaction tx, err := pool.Begin(ctx) if err != nil { return err } // Ensure transaction is properly closed defer func() { if p := recover(); p != nil { // If there was a panic, rollback and re-panic _ = tx.Rollback(ctx) panic(p) } else if err != nil { // If there was an error, rollback _ = tx.Rollback(ctx) } else { // If everything was successful, commit err = tx.Commit(ctx) } }() // Create Queries object with the transaction q := queries.New(tx) // Execute the function with the transaction-bound queries err = fn(q) return err } } ================================================ FILE: internal/service/invite/service.go ================================================ package invite import ( "context" "github.com/stashapp/stash-box/internal/queries" ) type Invite struct { queries *queries.Queries withTxn queries.WithTxnFunc } func NewInvite(queries *queries.Queries, withTxn queries.WithTxnFunc) *Invite { return &Invite{ queries: queries, withTxn: withTxn, } } // WithTxn executes a function within a transaction func (s *Invite) WithTxn(fn func(*queries.Queries) error) error { return s.withTxn(fn) } func (s *Invite) DestroyExpired(ctx context.Context) error { return s.withTxn(func(tx *queries.Queries) error { return tx.DestroyExpiredInvites(ctx) }) } ================================================ FILE: internal/service/mod_audit/mod_audit.go ================================================ package mod_audit import ( "context" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/internal/queries" ) // ModAuditService handles mod audit operations type ModAuditService struct { queries *queries.Queries } // NewModAuditService creates a new mod audit service func NewModAuditService(queries *queries.Queries) *ModAuditService { return &ModAuditService{ queries: queries, } } // GetModAuditCount returns the total count of audits matching the filter func (s *ModAuditService) GetModAuditCount(ctx context.Context, filter models.ModAuditQueryInput) (int, error) { var action queries.NullModAuditAction if filter.Action != nil { action = queries.NullModAuditAction{ ModAuditAction: queries.ModAuditAction(filter.Action.String()), Valid: true, } } var userID uuid.NullUUID if filter.UserID != nil { userID = uuid.NullUUID{UUID: *filter.UserID, Valid: true} } count, err := s.queries.GetModAuditCount(ctx, queries.GetModAuditCountParams{ Action: action, UserID: userID, }) if err != nil { return 0, err } return int(count), nil } // QueryModAudits returns audits matching the filter with pagination func (s *ModAuditService) QueryModAudits(ctx context.Context, filter models.ModAuditQueryInput) ([]models.ModAudit, error) { var action queries.NullModAuditAction if filter.Action != nil { action = queries.NullModAuditAction{ ModAuditAction: queries.ModAuditAction(filter.Action.String()), Valid: true, } } var userID uuid.NullUUID if filter.UserID != nil { userID = uuid.NullUUID{UUID: *filter.UserID, Valid: true} } offset := (filter.Page - 1) * filter.PerPage limit := filter.PerPage dbAudits, err := s.queries.QueryModAudits(ctx, queries.QueryModAuditsParams{ Action: action, UserID: userID, Limit: int32(limit), Offset: int32(offset), }) if err != nil { return nil, err } audits := make([]models.ModAudit, len(dbAudits)) for i, dbAudit := range dbAudits { audits[i] = models.ModAudit{ ID: dbAudit.ID, Action: string(dbAudit.Action), UserID: dbAudit.UserID, TargetID: dbAudit.TargetID, TargetType: dbAudit.TargetType, Data: string(dbAudit.Data), Reason: dbAudit.Reason, CreatedAt: dbAudit.CreatedAt, } } return audits, nil } // DeleteExpired removes mod audit records older than the specified number of days func (s *ModAuditService) DeleteExpired(ctx context.Context, retentionDays int) error { if retentionDays <= 0 { return nil } return s.queries.DeleteExpiredModAudits(ctx, int32(retentionDays)) } ================================================ FILE: internal/service/notification/service.go ================================================ package notification import ( "context" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/converter" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/internal/queries" "github.com/stashapp/stash-box/pkg/logger" ) type Notification struct { queries *queries.Queries withTxn queries.WithTxnFunc } func NewNotification(queries *queries.Queries, withTxn queries.WithTxnFunc) *Notification { return &Notification{ queries: queries, withTxn: withTxn, } } // WithTxn executes a function within a transaction func (s *Notification) WithTxn(fn func(*queries.Queries) error) error { return s.withTxn(fn) } func (s *Notification) TriggerSceneCreationNotifications(ctx context.Context, sceneID uuid.UUID) error { return s.queries.TriggerSceneCreationNotifications(ctx, sceneID) } func (s *Notification) TriggerPerformerEditNotifications(ctx context.Context, editID uuid.UUID) error { return s.queries.TriggerPerformerEditNotifications(ctx, editID) } func (s *Notification) TriggerStudioEditNotifications(ctx context.Context, editID uuid.UUID) error { return s.queries.TriggerStudioEditNotifications(ctx, editID) } func (s *Notification) TriggerSceneEditNotifications(ctx context.Context, editID uuid.UUID) error { return s.queries.TriggerSceneEditNotifications(ctx, editID) } func (s *Notification) TriggerEditCommentNotifications(ctx context.Context, commentID uuid.UUID) error { return s.queries.TriggerEditCommentNotifications(ctx, commentID) } func (s *Notification) TriggerDownvoteEditNotifications(ctx context.Context, editID uuid.UUID) error { return s.queries.TriggerDownvoteEditNotifications(ctx, editID) } func (s *Notification) TriggerFailedEditNotifications(ctx context.Context, editID uuid.UUID) error { return s.queries.TriggerFailedEditNotifications(ctx, editID) } func (s *Notification) TriggerUpdatedEditNotifications(ctx context.Context, editID uuid.UUID) error { return s.queries.TriggerUpdatedEditNotifications(ctx, editID) } func (s *Notification) GetNotificationsCount(ctx context.Context, userID uuid.UUID, unreadOnly bool, notificationType *models.NotificationEnum) (int, error) { var typeParam queries.NullNotificationType if notificationType != nil { typeParam = queries.NullNotificationType{ NotificationType: queries.NotificationType(*notificationType), Valid: true, } } count, err := s.queries.CountNotificationsByUser(ctx, queries.CountNotificationsByUserParams{ UserID: userID, UnreadOnly: unreadOnly, Type: typeParam, }) return int(count), err } func (s *Notification) GetNotifications(ctx context.Context, userID uuid.UUID, unreadOnly bool, page int, perPage int, notificationType *models.NotificationEnum) ([]models.Notification, error) { var notifications []queries.Notification var err error offset := (page - 1) * perPage limit := perPage var typeParam queries.NullNotificationType if notificationType != nil { typeParam = queries.NullNotificationType{ NotificationType: queries.NotificationType(*notificationType), Valid: true, } } if unreadOnly { notifications, err = s.queries.FindUnreadNotificationsByUser(ctx, queries.FindUnreadNotificationsByUserParams{ UserID: userID, Limit: int32(limit), Offset: int32(offset), Type: typeParam, }) } else { notifications, err = s.queries.FindNotificationsByUser(ctx, queries.FindNotificationsByUserParams{ UserID: userID, Limit: int32(limit), Offset: int32(offset), Type: typeParam, }) } if err != nil { return nil, err } return converter.NotificationsToModels(notifications), nil } // Update methods func (s *Notification) MarkAllRead(ctx context.Context, userID uuid.UUID) error { return s.queries.MarkAllNotificationsRead(ctx, userID) } func (s *Notification) MarkRead(ctx context.Context, userID uuid.UUID, notificationType models.NotificationEnum, id uuid.UUID) error { return s.queries.MarkNotificationRead(ctx, queries.MarkNotificationReadParams{ ID: id, UserID: userID, Type: queries.NotificationType(notificationType.String()), }) } // Maintenance methods func (s *Notification) DestroyExpired(ctx context.Context) error { return s.withTxn(func(tx *queries.Queries) error { return tx.DestroyExpiredNotifications(ctx) }) } func (s *Notification) UpdateNotificationSubscriptions(ctx context.Context, userID uuid.UUID, subscriptions []models.NotificationEnum) error { return s.withTxn(func(tx *queries.Queries) error { if err := tx.DeleteUserNotificationSubscriptions(ctx, userID); err != nil { return err } var params []queries.CreateUserNotificationSubscriptionsParams for _, sub := range subscriptions { params = append(params, queries.CreateUserNotificationSubscriptionsParams{ UserID: userID, Type: queries.NotificationType(sub), }) } _, err := tx.CreateUserNotificationSubscriptions(ctx, params) return err }) } func (s *Notification) OnApplyEdit(ctx context.Context, edit *models.Edit) { if (edit.Status == models.VoteStatusEnumAccepted.String() || edit.Status == models.VoteStatusEnumImmediateAccepted.String()) && edit.Operation == models.OperationEnumCreate.String() { if edit.TargetType == models.TargetTypeEnumScene.String() && edit.Operation == models.OperationEnumCreate.String() { scene, err := s.queries.GetEditTargetID(ctx, edit.ID) if err != nil { return } if err := s.TriggerSceneCreationNotifications(ctx, scene.ID); err != nil { logger.Errorf("Failed to trigger scene creation notifications: %v", err) } } } else if edit.Status == models.VoteStatusEnumImmediateRejected.String() || edit.Status == models.VoteStatusEnumRejected.String() || edit.Status == models.VoteStatusEnumFailed.String() { if err := s.TriggerFailedEditNotifications(ctx, edit.ID); err != nil { logger.Errorf("Failed to trigger failed edit notifications: %v", err) } } } func (s *Notification) OnCancelEdit(ctx context.Context, edit *models.Edit) { // Only send notification if the edit was force-rejected by an admin // Don't send notification if the user canceled their own edit if edit.Status == models.VoteStatusEnumImmediateRejected.String() { if err := s.TriggerFailedEditNotifications(ctx, edit.ID); err != nil { logger.Errorf("Failed to trigger failed edit notifications: %v", err) } } } func (s *Notification) OnCreateEdit(ctx context.Context, edit *models.Edit) { switch edit.TargetType { case models.TargetTypeEnumPerformer.String(): if err := s.TriggerPerformerEditNotifications(ctx, edit.ID); err != nil { logger.Errorf("Failed to trigger performer edit notifications: %v", err) } case models.TargetTypeEnumScene.String(): if err := s.TriggerSceneEditNotifications(ctx, edit.ID); err != nil { logger.Errorf("Failed to trigger scene edit notifications: %v", err) } case models.TargetTypeEnumStudio.String(): if err := s.TriggerStudioEditNotifications(ctx, edit.ID); err != nil { logger.Errorf("Failed to trigger studio edit notifications: %v", err) } } } func (s *Notification) OnUpdateEdit(ctx context.Context, edit *models.Edit) { if err := s.TriggerUpdatedEditNotifications(ctx, edit.ID); err != nil { logger.Errorf("Failed to trigger updated edit notifications: %v", err) } } func (s *Notification) OnEditDownvote(ctx context.Context, edit *models.Edit) { if err := s.TriggerDownvoteEditNotifications(ctx, edit.ID); err != nil { logger.Errorf("Failed to trigger downvote edit notifications: %v", err) } } func (s *Notification) OnEditComment(ctx context.Context, comment *models.EditComment) { if err := s.TriggerEditCommentNotifications(ctx, comment.ID); err != nil { logger.Errorf("Failed to trigger edit comment notifications: %v", err) } } ================================================ FILE: internal/service/performer/joins.go ================================================ package performer import ( "context" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/internal/queries" ) func createAliases(ctx context.Context, tx *queries.Queries, performerID uuid.UUID, aliases []string) error { var params []queries.CreatePerformerAliasesParams for _, alias := range aliases { params = append(params, queries.CreatePerformerAliasesParams{ PerformerID: performerID, Alias: alias, }) } _, err := tx.CreatePerformerAliases(ctx, params) return err } func updateAliases(ctx context.Context, tx *queries.Queries, performerID uuid.UUID, aliases []string) error { if err := tx.DeletePerformerAliases(ctx, performerID); err != nil { return err } return createAliases(ctx, tx, performerID, aliases) } func createTattoos(ctx context.Context, tx *queries.Queries, performerID uuid.UUID, tattoos []models.BodyModification) error { var params []queries.CreatePerformerTattoosParams for _, tattoo := range tattoos { params = append(params, queries.CreatePerformerTattoosParams{ PerformerID: performerID, Location: &tattoo.Location, Description: tattoo.Description, }) } _, err := tx.CreatePerformerTattoos(ctx, params) return err } func updateTattoos(ctx context.Context, tx *queries.Queries, performerID uuid.UUID, tattoos []models.BodyModification) error { if err := tx.DeletePerformerTattoos(ctx, performerID); err != nil { return err } return createTattoos(ctx, tx, performerID, tattoos) } func createPiercings(ctx context.Context, tx *queries.Queries, performerID uuid.UUID, piercings []models.BodyModification) error { var params []queries.CreatePerformerPiercingsParams for _, piercing := range piercings { params = append(params, queries.CreatePerformerPiercingsParams{ PerformerID: performerID, Location: &piercing.Location, Description: piercing.Description, }) } _, err := tx.CreatePerformerPiercings(ctx, params) return err } func updatePiercings(ctx context.Context, tx *queries.Queries, performerID uuid.UUID, piercings []models.BodyModification) error { if err := tx.DeletePerformerPiercings(ctx, performerID); err != nil { return err } return createPiercings(ctx, tx, performerID, piercings) } func createURLs(ctx context.Context, tx *queries.Queries, performerID uuid.UUID, urls []models.URL) error { var params []queries.CreatePerformerURLsParams for _, url := range urls { params = append(params, queries.CreatePerformerURLsParams{ PerformerID: performerID, Url: url.URL, SiteID: url.SiteID, }) } _, err := tx.CreatePerformerURLs(ctx, params) return err } func updateURLs(ctx context.Context, tx *queries.Queries, performerID uuid.UUID, urls []models.URL) error { if err := tx.DeletePerformerURLs(ctx, performerID); err != nil { return err } return createURLs(ctx, tx, performerID, urls) } func createImages(ctx context.Context, tx *queries.Queries, performerID uuid.UUID, images []uuid.UUID) error { var params []queries.CreatePerformerImagesParams for _, image := range images { params = append(params, queries.CreatePerformerImagesParams{ PerformerID: performerID, ImageID: image, }) } _, err := tx.CreatePerformerImages(ctx, params) return err } func updateImages(ctx context.Context, tx *queries.Queries, performerID uuid.UUID, images []uuid.UUID) error { // TODO Remove unused images if err := tx.DeletePerformerImages(ctx, performerID); err != nil { return err } return createImages(ctx, tx, performerID, images) } ================================================ FILE: internal/service/performer/query.go ================================================ package performer import ( "context" "fmt" "strings" sq "github.com/Masterminds/squirrel" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/auth" "github.com/stashapp/stash-box/internal/converter" "github.com/stashapp/stash-box/internal/models" queryhelper "github.com/stashapp/stash-box/internal/service/query" ) func (s *Performer) Query(ctx context.Context, input models.PerformerQueryInput) ([]models.Performer, error) { user := auth.GetCurrentUser(ctx) psql := sq.StatementBuilder.PlaceholderFormat(sq.Dollar) query := s.buildPerformerQuery(psql, input, user.ID, false) // Apply sort query = s.applyPerformerSort(query, input) // Apply pagination query = queryhelper.ApplyPagination(query, input.Page, input.PerPage) return queryhelper.ExecuteQuery(ctx, query, s.queries.DB(), converter.PerformerToModel, "QueryPerformers") } func (s *Performer) QueryCount(ctx context.Context, input models.PerformerQueryInput) (int, error) { user := auth.GetCurrentUser(ctx) psql := sq.StatementBuilder.PlaceholderFormat(sq.Dollar) query := s.buildPerformerQuery(psql, input, user.ID, true) return queryhelper.ExecuteCount(ctx, query, s.queries.DB(), "QueryPerformersCount") } func (s *Performer) buildPerformerQuery(psql sq.StatementBuilderType, input models.PerformerQueryInput, userID uuid.UUID, forCount bool) sq.SelectBuilder { var query sq.SelectBuilder needsStudioJoin := input.StudioID != nil // Build base query with studio join if needed if forCount { if needsStudioJoin { query = psql.Select("COUNT(DISTINCT performers.id)").From("performers"). Join(`( SELECT performer_id, MIN(date) as debut, MAX(date) AS last_scene, COUNT(*) as scene_count FROM scene_performers JOIN scenes ON scene_id = id AND studio_id = ? GROUP BY performer_id ) D ON performers.id = D.performer_id`, input.StudioID) } else { query = psql.Select("COUNT(*)").From("performers") } } else { if needsStudioJoin { query = psql.Select("performers.*").From("performers"). Join(`( SELECT performer_id, MIN(date) as debut, MAX(date) AS last_scene, COUNT(*) as scene_count FROM scene_performers JOIN scenes ON scene_id = id AND studio_id = ? GROUP BY performer_id ) D ON performers.id = D.performer_id`, input.StudioID) } else { query = psql.Select("performers.*").From("performers") } } // Filter by URL if input.URL != nil && *input.URL != "" { query = query. Join("performer_urls ON performers.id = performer_urls.performer_id"). Where(sq.Eq{"performer_urls.url": *input.URL}) } // Filter by name only if input.Name != nil && *input.Name != "" { searchTerm := "%" + *input.Name + "%" query = query.Where(sq.ILike{"performers.name": searchTerm}) } // Filter by names (searches name and disambiguation) if input.Names != nil && *input.Names != "" { searchTerm := "%" + *input.Names + "%" query = query.Where(sq.Or{ sq.ILike{"performers.name": searchTerm}, sq.ILike{"performers.disambiguation": searchTerm}, }) } // Filter by birth year if input.BirthYear != nil { query = queryhelper.ApplyIntCriterion(query, "EXTRACT(YEAR FROM to_date(performers.birthdate, 'YYYY-MM-DD'))::int", input.BirthYear) } // Filter by birthdate if input.Birthdate != nil { query = queryhelper.ApplyDateCriterion(query, "performers.birthdate", input.Birthdate) } // Filter by deathdate if input.Deathdate != nil { query = queryhelper.ApplyDateCriterion(query, "performers.deathdate", input.Deathdate) } // Filter by age if input.Age != nil { ageExpr := "EXTRACT(YEAR FROM AGE(COALESCE(to_date(performers.deathdate, 'YYYY-MM-DD'), CURRENT_DATE), to_date(performers.birthdate, 'YYYY-MM-DD')))::int" query = queryhelper.ApplyIntCriterion(query, ageExpr, input.Age) } // Filter by gender if input.Gender != nil && *input.Gender != "" { if *input.Gender == models.GenderFilterEnumUnknown { query = query.Where("performers.gender IS NULL") } else { query = query.Where(sq.Eq{"performers.gender": input.Gender.String()}) } } // Filter by ethnicity if input.Ethnicity != nil && *input.Ethnicity != "" { if *input.Ethnicity == models.EthnicityFilterEnumUnknown { query = query.Where("performers.ethnicity IS NULL") } else { query = query.Where(sq.Eq{"performers.ethnicity": input.Ethnicity.String()}) } } // Filter by favorite status if input.IsFavorite != nil { if *input.IsFavorite { query = query. Join("performer_favorites F ON performers.id = F.performer_id"). Where(sq.Eq{"F.user_id": userID}) } else { query = query. LeftJoin("performer_favorites F ON performers.id = F.performer_id AND F.user_id = ?", userID). Where("F.performer_id IS NULL") } } // Filter by performed with if input.PerformedWith != nil { subquery := ` performers.id IN ( SELECT SP.performer_id FROM scene_performers SP JOIN scene_performers SPP ON SP.scene_id = SPP.scene_id WHERE SPP.performer_id = ? AND SP.performer_id != ? GROUP BY SP.performer_id )` query = query.Where(sq.Expr(subquery, input.PerformedWith, input.PerformedWith)) } // String criteria if input.Disambiguation != nil { query = queryhelper.ApplyStringCriterion(query, "disambiguation", input.Disambiguation) } if input.Country != nil { query = queryhelper.ApplyStringCriterion(query, "country", input.Country) } // Only non-deleted performers query = query.Where(sq.Eq{"deleted": false}) return query } func (s *Performer) applyPerformerSort(query sq.SelectBuilder, input models.PerformerQueryInput) sq.SelectBuilder { sortField := "name" sortDir := "ASC" if input.Direction != "" { sortDir = strings.ToUpper(input.Direction.String()) } needsStudioJoin := input.StudioID != nil switch input.Sort { case models.PerformerSortEnumDebut: if !needsStudioJoin { query = query.LeftJoin(`( SELECT performer_id, MIN(date) as debut FROM scene_performers JOIN scenes ON scene_id = id GROUP BY performer_id ) D ON performers.id = D.performer_id`) } return query.OrderBy(fmt.Sprintf("debut %s NULLS LAST, name %s", sortDir, sortDir)) case models.PerformerSortEnumLastScene: if !needsStudioJoin { query = query.LeftJoin(`( SELECT performer_id, MAX(date) as last_scene FROM scene_performers JOIN scenes ON scene_id = id GROUP BY performer_id ) D ON performers.id = D.performer_id`) } return query.OrderBy(fmt.Sprintf("last_scene %s NULLS LAST, name %s", sortDir, sortDir)) case models.PerformerSortEnumSceneCount: if !needsStudioJoin { query = query.LeftJoin(`( SELECT performer_id, COUNT(*) as scene_count FROM scene_performers GROUP BY performer_id ) D ON performers.id = D.performer_id`) } return query.OrderBy(fmt.Sprintf("COALESCE(scene_count, 0) %s, name %s", sortDir, sortDir)) default: if input.Sort != "" { sortField = strings.ToLower(input.Sort.String()) } return query.OrderBy(fmt.Sprintf("%s %s", sortField, sortDir)) } } ================================================ FILE: internal/service/performer/service.go ================================================ package performer import ( "context" "encoding/json" "fmt" "strings" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/converter" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/internal/queries" "github.com/stashapp/stash-box/internal/service/errutil" ) // Performer handles performer-related operations type Performer struct { queries *queries.Queries withTxn queries.WithTxnFunc } // NewPerformer creates a new performer service func NewPerformer(queries *queries.Queries, withTxn queries.WithTxnFunc) *Performer { return &Performer{ queries: queries, withTxn: withTxn, } } // WithTxn executes a function within a transaction func (s *Performer) WithTxn(fn func(*queries.Queries) error) error { return s.withTxn(fn) } // Queries func (s *Performer) FindByID(ctx context.Context, id uuid.UUID) (*models.Performer, error) { performer, err := s.queries.FindPerformer(ctx, id) if err != nil { return nil, errutil.IgnoreNotFound(err) } return converter.PerformerToModelPtr(performer), nil } func (s *Performer) FindByName(ctx context.Context, name string) (*models.Performer, error) { performer, err := s.queries.FindPerformerByName(ctx, strings.ToUpper(name)) if err != nil { return nil, errutil.IgnoreNotFound(err) } return converter.PerformerToModelPtr(performer), nil } func (s *Performer) FindByAlias(ctx context.Context, alias string) (*models.Performer, error) { performer, err := s.queries.FindPerformerByAlias(ctx, strings.ToUpper(alias)) if err != nil { return nil, errutil.IgnoreNotFound(err) } return converter.PerformerToModelPtr(performer), nil } // Dataloader for performers func (s *Performer) LoadByIds(ctx context.Context, ids []uuid.UUID) ([]*models.Performer, []error) { if len(ids) == 0 { return make([]*models.Performer, 0), nil } performers, err := s.queries.FindPerformersByIds(ctx, ids) if err != nil { return nil, errutil.DuplicateError(err, len(ids)) } // Create a map for quick lookup m := make(map[uuid.UUID]*models.Performer) for _, performer := range performers { modelPerformer := converter.PerformerToModel(performer) m[performer.ID] = &modelPerformer } // Build result in the same order as input IDs result := make([]*models.Performer, len(ids)) for i, id := range ids { result[i] = m[id] } return result, nil } // Dataloder for merge target IDs for performers func (s *Performer) LoadMergeIDsByPerformerIDs(ctx context.Context, ids []uuid.UUID) ([][]uuid.UUID, []error) { if len(ids) == 0 { return make([][]uuid.UUID, 0), nil } merges, err := s.queries.FindMergeIDsByPerformerIds(ctx, ids) if err != nil { return nil, errutil.DuplicateError(err, len(ids)) } // Group results by performer ID m := make(map[uuid.UUID][]uuid.UUID) for _, merge := range merges { m[merge.PerformerID] = append(m[merge.PerformerID], merge.MergeID) } // Build result in the same order as input IDs result := make([][]uuid.UUID, len(ids)) for i, id := range ids { result[i] = m[id] } return result, nil } // Dataloader for merge source IDs for performers func (s *Performer) LoadMergeIDsBySourcePerformerIDs(ctx context.Context, ids []uuid.UUID) ([][]uuid.UUID, []error) { if len(ids) == 0 { return make([][]uuid.UUID, 0), nil } merges, err := s.queries.FindMergeIDsBySourcePerformerIds(ctx, ids) if err != nil { return nil, errutil.DuplicateError(err, len(ids)) } // Group results by performer ID m := make(map[uuid.UUID][]uuid.UUID) for _, merge := range merges { m[merge.PerformerID] = append(m[merge.PerformerID], merge.MergeID) } // Build result in the same order as input IDs result := make([][]uuid.UUID, len(ids)) for i, id := range ids { result[i] = m[id] } return result, nil } // Dataloader for aliases for multiple performers func (s *Performer) LoadAliases(ctx context.Context, ids []uuid.UUID) ([][]string, []error) { if len(ids) == 0 { return make([][]string, 0), nil } aliases, err := s.queries.FindPerformerAliasesByIds(ctx, ids) if err != nil { return nil, errutil.DuplicateError(err, len(ids)) } // Group results by performer ID m := make(map[uuid.UUID][]string) for _, alias := range aliases { m[alias.PerformerID] = append(m[alias.PerformerID], alias.Alias) } // Build result in the same order as input IDs result := make([][]string, len(ids)) for i, id := range ids { result[i] = m[id] } return result, nil } // Dataloader for tattoos for multiple performers func (s *Performer) LoadTattoos(ctx context.Context, ids []uuid.UUID) ([][]models.BodyModification, []error) { if len(ids) == 0 { return make([][]models.BodyModification, 0), nil } tattoos, err := s.queries.FindPerformerTattoosByIds(ctx, ids) if err != nil { return nil, errutil.DuplicateError(err, len(ids)) } // Group results by performer ID m := make(map[uuid.UUID][]models.BodyModification) for _, tattoo := range tattoos { bodyMod := models.BodyModification{ Description: tattoo.Description, } if tattoo.Location != nil { bodyMod.Location = *tattoo.Location } m[tattoo.PerformerID] = append(m[tattoo.PerformerID], bodyMod) } // Build result in the same order as input IDs result := make([][]models.BodyModification, len(ids)) for i, id := range ids { result[i] = m[id] } return result, nil } // Dataloader for piercings for multiple performers func (s *Performer) LoadPiercings(ctx context.Context, ids []uuid.UUID) ([][]models.BodyModification, []error) { if len(ids) == 0 { return make([][]models.BodyModification, 0), nil } piercings, err := s.queries.FindPerformerPiercingsByIds(ctx, ids) if err != nil { return nil, errutil.DuplicateError(err, len(ids)) } // Group results by performer ID m := make(map[uuid.UUID][]models.BodyModification) for _, piercing := range piercings { bodyMod := models.BodyModification{ Description: piercing.Description, } if piercing.Location != nil { bodyMod.Location = *piercing.Location } m[piercing.PerformerID] = append(m[piercing.PerformerID], bodyMod) } // Build result in the same order as input IDs result := make([][]models.BodyModification, len(ids)) for i, id := range ids { result[i] = m[id] } return result, nil } // Dataloader for URLs for multiple performers func (s *Performer) LoadURLs(ctx context.Context, ids []uuid.UUID) ([][]models.URL, []error) { if len(ids) == 0 { return make([][]models.URL, 0), nil } urls, err := s.queries.FindPerformerUrlsByIds(ctx, ids) if err != nil { return nil, errutil.DuplicateError(err, len(ids)) } // Group results by performer ID m := make(map[uuid.UUID][]models.URL) for _, url := range urls { urlModel := models.URL{ URL: url.Url, SiteID: url.SiteID, } m[url.PerformerID] = append(m[url.PerformerID], urlModel) } // Build result in the same order as input IDs result := make([][]models.URL, len(ids)) for i, id := range ids { result[i] = m[id] } return result, nil } func (s *Performer) GetAliases(ctx context.Context, performerID uuid.UUID) ([]string, error) { return s.queries.GetPerformerAliases(ctx, performerID) } func (s *Performer) GetTattoos(ctx context.Context, performerID uuid.UUID) ([]models.BodyModification, error) { tattoos, err := s.queries.GetPerformerTattoos(ctx, performerID) if err != nil { return nil, err } var result []models.BodyModification for _, tattoo := range tattoos { location := "" if tattoo.Location != nil { location = *tattoo.Location } result = append(result, models.BodyModification{ Location: location, Description: tattoo.Description, }) } return result, nil } func (s *Performer) GetPiercings(ctx context.Context, performerID uuid.UUID) ([]models.BodyModification, error) { piercings, err := s.queries.GetPerformerPiercings(ctx, performerID) if err != nil { return nil, err } var result []models.BodyModification for _, piercing := range piercings { location := "" if piercing.Location != nil { location = *piercing.Location } result = append(result, models.BodyModification{ Location: location, Description: piercing.Description, }) } return result, nil } func (s *Performer) GetURLs(ctx context.Context, performerID uuid.UUID) ([]models.URL, error) { urls, err := s.queries.GetPerformerURLs(ctx, performerID) if err != nil { return nil, err } var result []models.URL for _, url := range urls { result = append(result, models.URL{ URL: url.Url, SiteID: url.SiteID, }) } return result, nil } // Mutations func (s *Performer) Create(ctx context.Context, input models.PerformerCreateInput) (*models.Performer, error) { id, err := uuid.NewV7() if err != nil { return nil, err } // Populate a new performer from the input newPerformer := converter.PerformerCreateInputToPerformer(input) newPerformer.ID = id var performer *models.Performer err = s.withTxn(func(tx *queries.Queries) error { dbPerformer, err := tx.CreatePerformer(ctx, converter.PerformerToCreateParams(newPerformer)) if err != nil { return err } performer = converter.PerformerToModelPtr(dbPerformer) if err := createAliases(ctx, tx, id, input.Aliases); err != nil { return err } if err := createURLs(ctx, tx, id, input.Urls); err != nil { return err } if err := createPiercings(ctx, tx, id, converter.BodyModInputToModel(input.Piercings)); err != nil { return err } if err := createTattoos(ctx, tx, id, converter.BodyModInputToModel(input.Tattoos)); err != nil { return err } return createImages(ctx, tx, id, input.ImageIds) }) return performer, err } func (s *Performer) Update(ctx context.Context, input models.PerformerUpdateInput) (*models.Performer, error) { var performer *models.Performer err := s.withTxn(func(tx *queries.Queries) error { // get the existing performer and modify it updatedPerformer, err := s.FindByID(ctx, input.ID) if err != nil { return err } // Populate performer from the input converter.UpdatePerformerFromUpdateInput(updatedPerformer, input) dbPerformer, err := tx.UpdatePerformer(ctx, converter.PerformerToUpdateParams(*updatedPerformer)) if err != nil { return err } performer = converter.PerformerToModelPtr(dbPerformer) // Save the aliases if err := updateAliases(ctx, tx, performer.ID, input.Aliases); err != nil { return err } // Save the URLs if err := updateURLs(ctx, tx, performer.ID, input.Urls); err != nil { return err } // Save the Tattoos if err := updateTattoos(ctx, tx, performer.ID, converter.BodyModInputToModel(input.Tattoos)); err != nil { return err } // Save the Piercings if err := updatePiercings(ctx, tx, performer.ID, converter.BodyModInputToModel(input.Piercings)); err != nil { return err } // Update images return updateImages(ctx, tx, performer.ID, input.ImageIds) }) // Commit if err != nil { return nil, err } return performer, nil } func (s *Performer) Delete(ctx context.Context, id uuid.UUID) error { return s.queries.DeletePerformer(ctx, id) } func (s *Performer) Favorite(ctx context.Context, userID uuid.UUID, performerID uuid.UUID, favorite bool) error { performer, err := s.queries.FindPerformer(ctx, performerID) if err != nil { return fmt.Errorf("performer not found") } if performer.Deleted { return fmt.Errorf("performer is deleted, unable to make favorite") } if favorite { return s.queries.CreatePerformerFavorite(ctx, queries.CreatePerformerFavoriteParams{ UserID: userID, PerformerID: performerID, }) } return s.queries.DeletePerformerFavorite(ctx, queries.DeletePerformerFavoriteParams{ UserID: userID, PerformerID: performerID, }) } func (s *Performer) FindExistingPerformers(ctx context.Context, input models.QueryExistingPerformerInput) ([]models.Performer, error) { urls := input.Urls if input.Name == nil && len(urls) == 0 { return nil, nil } rows, err := s.queries.FindExistingPerformers(ctx, queries.FindExistingPerformersParams{ Name: input.Name, Disambiguation: input.Disambiguation, Urls: urls, }) return converter.PerformersToModels(rows), err } func (s *Performer) SearchPerformer(ctx context.Context, term string, limit *int, page *int, perPage *int, filter *models.PerformerSearchFilter) (*models.PerformerQuery, error) { trimmedQuery := strings.TrimSpace(strings.ToLower(term)) performerID, err := uuid.FromString(trimmedQuery) if err == nil { var performers []models.Performer performer, err := s.queries.FindPerformer(ctx, performerID) if err == nil { performers = append(performers, converter.PerformerToModel(performer)) } return &models.PerformerQuery{ SearchResults: &models.PerformerSearchResults{ Performers: performers, Count: len(performers), }, }, errutil.IgnoreNotFound(err) } searchLimit := 10 searchOffset := 0 if perPage != nil && *perPage > 0 { searchLimit = *perPage } else if limit != nil && *limit > 0 { searchLimit = *limit } if page != nil && *page > 1 { searchOffset = (*page - 1) * searchLimit } if strings.HasPrefix(trimmedQuery, "https://") || strings.HasPrefix(trimmedQuery, "http://") { rows, err := s.queries.FindPerformersByURL(ctx, queries.FindPerformersByURLParams{ Url: &trimmedQuery, Limit: int32(searchLimit), }) performers := converter.PerformersToModels(rows) return &models.PerformerQuery{ SearchResults: &models.PerformerSearchResults{ Performers: performers, Count: len(performers), }, }, err } var filterGender *string if filter != nil { if filter.Gender != nil { genderStr := string(*filter.Gender) filterGender = &genderStr } } rows, err := s.queries.SearchPerformersWithFacets(ctx, queries.SearchPerformersWithFacetsParams{ Term: &trimmedQuery, Limit: int32(searchLimit), Offset: int32(searchOffset), FilterGender: filterGender, }) if err != nil { return nil, err } ids := make([]uuid.UUID, len(rows)) for i, row := range rows { ids[i] = row.PerformerID } performerPtrs, _ := s.LoadByIds(ctx, ids) performers := make([]models.Performer, 0, len(performerPtrs)) for _, p := range performerPtrs { if p != nil { performers = append(performers, *p) } } // Parse facets and count from the first row (all rows have the same aggregated values) var facets *models.PerformerSearchFacets count := 0 if len(rows) > 0 { facets = parsePerformerFacets(rows[0].GenderFacets) count = parseParadeDBCount(rows[0].TotalCount) } return &models.PerformerQuery{ SearchResults: &models.PerformerSearchResults{ Performers: performers, Count: count, Facets: facets, }, }, nil } type paradeDBCountResult struct { Value float64 `json:"value"` } func parseParadeDBCount(raw any) int { if raw == nil { return 0 } jsonBytes, err := json.Marshal(raw) if err != nil { return 0 } var result paradeDBCountResult if err := json.Unmarshal(jsonBytes, &result); err != nil { return 0 } return int(result.Value) } type paradeDBFacetResult struct { Buckets []paradeDBBucket `json:"buckets"` } type paradeDBBucket struct { Key string `json:"key"` DocCount int `json:"doc_count"` } func parsePerformerFacets(genderFacetsRaw any) *models.PerformerSearchFacets { facets := &models.PerformerSearchFacets{} if genderFacetsRaw != nil { if genderBytes, err := json.Marshal(genderFacetsRaw); err == nil { var genderResult paradeDBFacetResult if err := json.Unmarshal(genderBytes, &genderResult); err == nil { for _, bucket := range genderResult.Buckets { if gender := models.GenderEnum(bucket.Key); gender.IsValid() { facets.Genders = append(facets.Genders, models.GenderFacet{ Gender: gender, Count: bucket.DocCount, }) } } } } } return facets } func (s *Performer) LoadIsFavorite(ctx context.Context, userID uuid.UUID, ids []uuid.UUID) ([]bool, []error) { favorites, err := s.queries.FindPerformerFavoritesByIds(ctx, queries.FindPerformerFavoritesByIdsParams{ PerformerIds: ids, UserID: userID, }) if err != nil { return nil, errutil.DuplicateError(err, len(ids)) } result := make([]bool, len(ids)) favoriteMap := make(map[uuid.UUID]bool) for _, favorite := range favorites { favoriteMap[favorite.PerformerID] = favorite.IsFavorite } for i, id := range ids { result[i] = favoriteMap[id] } return result, make([]error, len(ids)) } ================================================ FILE: internal/service/query/criterion.go ================================================ package query import ( "fmt" sq "github.com/Masterminds/squirrel" "github.com/stashapp/stash-box/internal/models" ) // ApplyMultiIDCriterion applies multi-ID criterion (includes/includes_all/excludes) // Modifies the query pointer in place // tableName: the main table name (e.g., "scenes") // joinTable: the join table name (e.g., "scene_performers") // fkColumn: the foreign key column in the join table referencing the main table (e.g., "scene_id") // joinField: the field in the join table to filter on (e.g., "performer_id") func ApplyMultiIDCriterion(query *sq.SelectBuilder, tableName, joinTable, fkColumn, joinField string, criterion *models.MultiIDCriterionInput) error { switch criterion.Modifier { case models.CriterionModifierIncludes: // includes any of the provided ids subquery := sq.Select(fmt.Sprintf("DISTINCT %s", fkColumn)). From(joinTable). Where(sq.Eq{joinField: criterion.Value}) *query = query.JoinClause(sq.Expr(fmt.Sprintf("INNER JOIN (?) AS %s_filter ON %s.id = %s_filter.%s", joinTable, tableName, joinTable, fkColumn), subquery)) case models.CriterionModifierIncludesAll: // includes all of the provided ids subquery := sq.Select(fkColumn). From(joinTable). Where(sq.Eq{joinField: criterion.Value}). GroupBy(fkColumn). Having(sq.Eq{"COUNT(*)": len(criterion.Value)}) *query = query.JoinClause(sq.Expr(fmt.Sprintf("INNER JOIN (?) AS %s_filter ON %s.id = %s_filter.%s", joinTable, tableName, joinTable, fkColumn), subquery)) case models.CriterionModifierExcludes: // excludes all of the provided ids subquery := sq.Select(fkColumn). From(joinTable). Where(sq.Eq{joinField: criterion.Value}) *query = query.Where(sq.Expr(fmt.Sprintf("%s.id NOT IN (?)", tableName), subquery)) default: return fmt.Errorf("unsupported modifier %s for %s.%s", criterion.Modifier, joinTable, joinField) } return nil } // ApplyIDCriterion applies ID criterion for a direct column (equals, not equals, includes, excludes, is null, not null) // Returns the modified query func ApplyIDCriterion(query sq.SelectBuilder, field string, criterion *models.IDCriterionInput) sq.SelectBuilder { switch criterion.Modifier { case models.CriterionModifierEquals: if len(criterion.Value) > 0 { return query.Where(sq.Eq{field: criterion.Value[0]}) } return query case models.CriterionModifierNotEquals: if len(criterion.Value) > 0 { return query.Where(sq.NotEq{field: criterion.Value[0]}) } return query case models.CriterionModifierIncludes: return query.Where(sq.Eq{field: criterion.Value}) case models.CriterionModifierExcludes: return query.Where(sq.NotEq{field: criterion.Value}) case models.CriterionModifierIsNull: return query.Where(field + " IS NULL") case models.CriterionModifierNotNull: return query.Where(field + " IS NOT NULL") default: return query } } // ApplyIntCriterion applies integer criterion (equals, not equals, greater than, less than, is null, not null) // Returns the modified query func ApplyIntCriterion(query sq.SelectBuilder, field string, criterion *models.IntCriterionInput) sq.SelectBuilder { switch criterion.Modifier { case models.CriterionModifierEquals: return query.Where(sq.Eq{field: criterion.Value}) case models.CriterionModifierNotEquals: return query.Where(sq.NotEq{field: criterion.Value}) case models.CriterionModifierGreaterThan: return query.Where(sq.Gt{field: criterion.Value}) case models.CriterionModifierLessThan: return query.Where(sq.Lt{field: criterion.Value}) case models.CriterionModifierIsNull: return query.Where(field + " IS NULL") case models.CriterionModifierNotNull: return query.Where(field + " IS NOT NULL") default: return query } } // ApplyStringCriterion applies string criterion (equals, not equals, is null, not null) // Returns the modified query func ApplyStringCriterion(query sq.SelectBuilder, field string, criterion *models.StringCriterionInput) sq.SelectBuilder { switch criterion.Modifier { case models.CriterionModifierEquals: return query.Where(sq.Eq{field: criterion.Value}) case models.CriterionModifierNotEquals: return query.Where(sq.NotEq{field: criterion.Value}) case models.CriterionModifierIsNull: return query.Where(field + " IS NULL") case models.CriterionModifierNotNull: return query.Where(field + " IS NOT NULL") default: return query } } // ApplyDateCriterion applies date criterion (equals, not equals, greater than, less than, is null, not null) // Returns the modified query func ApplyDateCriterion(query sq.SelectBuilder, field string, criterion *models.DateCriterionInput) sq.SelectBuilder { switch criterion.Modifier { case models.CriterionModifierEquals: return query.Where(sq.Eq{field: criterion.Value}) case models.CriterionModifierNotEquals: return query.Where(sq.NotEq{field: criterion.Value}) case models.CriterionModifierGreaterThan: return query.Where(sq.Gt{field: criterion.Value}) case models.CriterionModifierLessThan: return query.Where(sq.Lt{field: criterion.Value}) case models.CriterionModifierIsNull: return query.Where(field + " IS NULL") case models.CriterionModifierNotNull: return query.Where(field + " IS NOT NULL") default: return query } } ================================================ FILE: internal/service/query/helpers.go ================================================ package query import ( "context" "fmt" "strings" sq "github.com/Masterminds/squirrel" "github.com/jackc/pgx/v5" "github.com/stashapp/stash-box/internal/queries" ) // ApplyPagination applies pagination to a query with default values func ApplyPagination(query sq.SelectBuilder, page, perPage int) sq.SelectBuilder { if page <= 0 { page = 1 } if perPage <= 0 { perPage = 25 } offset := (page - 1) * perPage return query.Limit(uint64(perPage)).Offset(uint64(offset)) } // ApplySortParams applies sorting to query with optional table prefix // If tablePrefix is empty, no prefix is added to the field name func ApplySortParams(query sq.SelectBuilder, tablePrefix string, sort, direction fmt.Stringer, defaultField, defaultDir string) sq.SelectBuilder { sortField := defaultField sortDir := defaultDir if sort != nil && sort.String() != "" { sortField = strings.ToLower(sort.String()) } if direction != nil && direction.String() != "" { sortDir = strings.ToUpper(direction.String()) } if tablePrefix != "" { return query.OrderBy(fmt.Sprintf("%s.%s %s", tablePrefix, sortField, sortDir)) } return query.OrderBy(fmt.Sprintf("%s %s", sortField, sortDir)) } // ExecuteQuery executes a squirrel query and converts results using a generic converter function // If queryName is provided, it prepends a sqlc-style comment for better span naming in traces func ExecuteQuery[T any, M any](ctx context.Context, query sq.SelectBuilder, db queries.DBTX, converter func(T) M, queryName string) ([]M, error) { sql, args, err := query.ToSql() if err != nil { return nil, err } // Prepend query name comment for tracing if provided if queryName != "" { sql = fmt.Sprintf("-- name: %s\n%s", queryName, sql) } rows, err := db.Query(ctx, sql, args...) if err != nil { return nil, err } defer rows.Close() var results []M for rows.Next() { dbEntity, err := pgx.RowToStructByPos[T](rows) if err != nil { return nil, err } results = append(results, converter(dbEntity)) } if err = rows.Err(); err != nil { return nil, err } return results, nil } // ExecuteCount executes a count query and returns the result as an int // If queryName is provided, it prepends a sqlc-style comment for better span naming in traces func ExecuteCount(ctx context.Context, query sq.SelectBuilder, db queries.DBTX, queryName string) (int, error) { sql, args, err := query.ToSql() if err != nil { return 0, err } // Prepend query name comment for tracing if provided if queryName != "" { sql = fmt.Sprintf("-- name: %s\n%s", queryName, sql) } var count int64 err = db.QueryRow(ctx, sql, args...).Scan(&count) return int(count), err } ================================================ FILE: internal/service/scene/query.go ================================================ package scene import ( "context" "fmt" "strings" sq "github.com/Masterminds/squirrel" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/auth" "github.com/stashapp/stash-box/internal/converter" "github.com/stashapp/stash-box/internal/models" queryhelper "github.com/stashapp/stash-box/internal/service/query" ) func (s *Scene) Query(ctx context.Context, input models.SceneQueryInput) ([]models.Scene, error) { user := auth.GetCurrentUser(ctx) psql := sq.StatementBuilder.PlaceholderFormat(sq.Dollar) query, err := s.buildSceneQuery(psql, input, user.ID, false) if err != nil { return nil, err } return queryhelper.ExecuteQuery(ctx, query, s.queries.DB(), converter.SceneToModel, "QueryScenes") } func (s *Scene) QueryCount(ctx context.Context, input models.SceneQueryInput) (int, error) { user := auth.GetCurrentUser(ctx) psql := sq.StatementBuilder.PlaceholderFormat(sq.Dollar) // Build the query selecting scenes.id (not doing a count yet) // This allows GROUP BY to work properly innerQuery, err := s.buildSceneQuery(psql, input, user.ID, true) if err != nil { return 0, err } // Replace the SELECT with just scenes.id for the subquery innerQuery = psql.Select("scenes.id").FromSelect(innerQuery, "scenes") // Wrap in a COUNT query countQuery := psql.Select("COUNT(*)").FromSelect(innerQuery, "subquery") return queryhelper.ExecuteCount(ctx, countQuery, s.queries.DB(), "QueryScenesCount") } func (s *Scene) buildSceneQuery(psql sq.StatementBuilderType, input models.SceneQueryInput, userID uuid.UUID, forCount bool) (sq.SelectBuilder, error) { query := psql.Select("scenes.*").From("scenes") // Filter by URL if input.URL != nil && *input.URL != "" { query = query. Join("scene_urls ON scenes.id = scene_urls.scene_id"). Where(sq.Eq{"scene_urls.url": *input.URL}) } // Filter by parent studio if input.ParentStudio != nil { query = query. Join("studios ON scenes.studio_id = studios.id"). Where(sq.Or{ sq.Eq{"studios.parent_studio_id": *input.ParentStudio}, sq.Eq{"studios.id": *input.ParentStudio}, }) } // Filter by performers if input.Performers != nil && len(input.Performers.Value) > 0 { if err := queryhelper.ApplyMultiIDCriterion(&query, "scenes", "scene_performers", "scene_id", "performer_id", input.Performers); err != nil { return query, err } } // Filter by tags if input.Tags != nil && len(input.Tags.Value) > 0 { if err := queryhelper.ApplyMultiIDCriterion(&query, "scenes", "scene_tags", "scene_id", "tag_id", input.Tags); err != nil { return query, err } } // Filter by fingerprints if input.Fingerprints != nil && len(input.Fingerprints.Value) > 0 { placeholders := make([]string, len(input.Fingerprints.Value)) args := make([]interface{}, len(input.Fingerprints.Value)) for i, hash := range input.Fingerprints.Value { placeholders[i] = "?" args[i] = hash } query = query.Join(fmt.Sprintf(`( SELECT scene_id FROM scene_fingerprints SFP JOIN fingerprints FP ON SFP.fingerprint_id = FP.id WHERE FP.hash IN (%s) GROUP BY scene_id ) T ON scenes.id = T.scene_id`, strings.Join(placeholders, ",")), args...) } // Filter by has fingerprint submissions if input.HasFingerprintSubmissions != nil && *input.HasFingerprintSubmissions { query = query.Join(`( SELECT scene_id FROM scene_fingerprints WHERE user_id = ? GROUP BY scene_id ) SFP ON scenes.id = SFP.scene_id`, userID) } // Filter by text (title and details) if input.Text != nil && *input.Text != "" { searchTerm := "%" + *input.Text + "%" query = query.Where(sq.Or{ sq.ILike{"scenes.title": searchTerm}, sq.ILike{"scenes.details": searchTerm}, }) } // Filter by title only if input.Title != nil && *input.Title != "" { searchTerm := "%" + *input.Title + "%" query = query.Where(sq.ILike{"scenes.title": searchTerm}) } // Filter by studios if input.Studios != nil && len(input.Studios.Value) > 0 { switch input.Studios.Modifier { case models.CriterionModifierEquals: query = query.Where(sq.Eq{"scenes.studio_id": input.Studios.Value[0]}) case models.CriterionModifierNotEquals: query = query.Where(sq.NotEq{"scenes.studio_id": input.Studios.Value[0]}) case models.CriterionModifierIsNull: query = query.Where("scenes.studio_id IS NULL") case models.CriterionModifierNotNull: query = query.Where("scenes.studio_id IS NOT NULL") case models.CriterionModifierIncludes: query = query.Where(sq.Eq{"scenes.studio_id": input.Studios.Value}) case models.CriterionModifierExcludes: query = query.Where(sq.NotEq{"scenes.studio_id": input.Studios.Value}) default: return query, fmt.Errorf("unsupported modifier %s for scenes.studio_id", input.Studios.Modifier) } } // Filter by date if input.Date != nil { switch input.Date.Modifier { case models.CriterionModifierEquals: query = query.Where(sq.Eq{"scenes.date": input.Date.Value}) case models.CriterionModifierNotEquals: query = query.Where(sq.NotEq{"scenes.date": input.Date.Value}) case models.CriterionModifierGreaterThan: query = query.Where(sq.Gt{"scenes.date": input.Date.Value}) case models.CriterionModifierLessThan: query = query.Where(sq.Lt{"scenes.date": input.Date.Value}) case models.CriterionModifierIsNull: query = query.Where("scenes.date IS NULL") case models.CriterionModifierNotNull: query = query.Where("scenes.date IS NOT NULL") default: return query, fmt.Errorf("unsupported modifier %s for scenes.date", input.Date.Modifier) } } // Filter by favorites if input.Favorites != nil { var clauses []string var args []interface{} if *input.Favorites == models.FavoriteFilterPerformer || *input.Favorites == models.FavoriteFilterAll { clauses = append(clauses, `( SELECT scene_id FROM performer_favorites PF JOIN scene_performers SP ON PF.performer_id = SP.performer_id WHERE PF.user_id = ? )`) args = append(args, userID) } if *input.Favorites == models.FavoriteFilterStudio || *input.Favorites == models.FavoriteFilterAll { clauses = append(clauses, `( SELECT S.id FROM studio_favorites SF JOIN scenes S ON SF.studio_id = S.studio_id WHERE SF.user_id = ? )`) args = append(args, userID) } if len(clauses) > 0 { query = query.Where(sq.Expr("scenes.id IN ("+strings.Join(clauses, " UNION ")+")", args...)) } } // Only non-deleted scenes query = query.Where(sq.Eq{"scenes.deleted": false}) // Apply sort and pagination if input.Sort == models.SceneSortEnumTrending { // Check if we can optimize by limiting the trending subquery // This is only safe when there are no other filters applied hasOtherFilters := input.URL != nil || input.ParentStudio != nil || (input.Performers != nil && len(input.Performers.Value) > 0) || (input.Tags != nil && len(input.Tags.Value) > 0) || (input.Fingerprints != nil && len(input.Fingerprints.Value) > 0) || (input.HasFingerprintSubmissions != nil && *input.HasFingerprintSubmissions) || (input.Text != nil && *input.Text != "") || (input.Title != nil && *input.Title != "") || (input.Studios != nil && len(input.Studios.Value) > 0) || input.Date != nil || input.Favorites != nil if !hasOtherFilters && !forCount { // Optimize: limit the trending subquery directly // Note: Use manual pagination here since we're limiting in the subquery page := 1 perPage := 25 if input.Page > 0 { page = input.Page } if input.PerPage > 0 { perPage = input.PerPage } offset := (page - 1) * perPage query = query.Join(fmt.Sprintf(`( SELECT scene_id, COUNT(*) AS count FROM scene_fingerprints WHERE created_at >= (now()::DATE - 7) GROUP BY scene_id ORDER BY count DESC LIMIT %d OFFSET %d ) TRENDING ON scenes.id = TRENDING.scene_id`, perPage, offset)) query = query.OrderBy("TRENDING.count DESC, TRENDING.scene_id DESC") // Don't apply pagination again below since we already limited in the subquery } else { // Standard trending query without optimization query = query.Join(`( SELECT scene_id, COUNT(*) AS count FROM scene_fingerprints WHERE created_at >= (now()::DATE - 7) GROUP BY scene_id ) TRENDING ON scenes.id = TRENDING.scene_id`) if !forCount { query = query.OrderBy("TRENDING.count DESC, TRENDING.scene_id DESC") query = queryhelper.ApplyPagination(query, input.Page, input.PerPage) } } } else if !forCount { // Only apply sorting for non-count queries sortField := "title" sortDir := "ASC" if input.Sort != "" { sortField = strings.ToLower(input.Sort.String()) } if input.Direction != "" { sortDir = strings.ToUpper(input.Direction.String()) } secondary := "title" if input.Sort != models.SceneSortEnumTitle { secondary = "id" } query = query.OrderBy(fmt.Sprintf("scenes.%s %s, scenes.%s %s", sortField, sortDir, secondary, sortDir)) query = queryhelper.ApplyPagination(query, input.Page, input.PerPage) } return query, nil } ================================================ FILE: internal/service/scene/service.go ================================================ package scene import ( "context" "encoding/json" "errors" "fmt" "github.com/gofrs/uuid" "github.com/jackc/pgx/v5" "github.com/stashapp/stash-box/internal/auth" "github.com/stashapp/stash-box/internal/config" "github.com/stashapp/stash-box/internal/converter" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/internal/queries" "github.com/stashapp/stash-box/internal/service/errutil" ) // Scene handles scene-related operations type Scene struct { queries *queries.Queries withTxn queries.WithTxnFunc } // NewScene creates a new scene service func NewScene(queries *queries.Queries, withTxn queries.WithTxnFunc) *Scene { return &Scene{ queries: queries, withTxn: withTxn, } } // WithTxn executes a function within a transaction func (s *Scene) WithTxn(fn func(*queries.Queries) error) error { return s.withTxn(fn) } // Queries func (s *Scene) FindByID(ctx context.Context, id uuid.UUID) (*models.Scene, error) { scene, err := s.queries.FindScene(ctx, id) if err != nil { return nil, errutil.IgnoreNotFound(err) } return converter.SceneToModelPtr(scene), nil } func (s *Scene) FindByURL(ctx context.Context, url string, limit int) ([]models.Scene, error) { scenes, err := s.queries.FindSceneByURL(ctx, queries.FindSceneByURLParams{ Url: &url, Limit: int32(limit), }) return converter.ScenesToModels(scenes), err } func (s *Scene) FindScenesBySceneFingerprints(ctx context.Context, sceneFingerprints [][]models.FingerprintQueryInput) ([][]*models.Scene, error) { var fingerprints []models.FingerprintQueryInput for _, scene := range sceneFingerprints { fingerprints = append(fingerprints, scene...) } var phashes []int64 var hashes []int64 distance := config.GetPHashDistance() for _, fp := range fingerprints { if fp.Algorithm == models.FingerprintAlgorithmPhash && distance > 0 { phashes = append(phashes, fp.Hash.Int64()) } else { hashes = append(hashes, fp.Hash.Int64()) } } rows, err := s.queries.FindScenesByFullFingerprintsWithHash(ctx, queries.FindScenesByFullFingerprintsWithHashParams{ Phashes: phashes, Hashes: hashes, Distance: distance, }) if err != nil || len(rows) == 0 { return make([][]*models.Scene, len(sceneFingerprints)), err } sceneMap := make(map[models.FingerprintHash][]models.Scene) for _, row := range rows { scene := converter.SceneToModel(row.Scene) sceneMap[models.FingerprintHash(row.Hash)] = append(sceneMap[models.FingerprintHash(row.Hash)], scene) } // Deduplicate list of scenes for each group of fingerprints var result = make([][]*models.Scene, len(sceneFingerprints)) for i, fingerprints := range sceneFingerprints { // Track which scenes we've already added for this group to avoid duplicates seenScenes := make(map[string]bool) for _, fp := range fingerprints { scenes, match := sceneMap[fp.Hash] if match { // Add all scenes that match this fingerprint for _, scene := range scenes { // Only add the scene if we haven't already added it for this fingerprint group sceneID := scene.ID.String() if !seenScenes[sceneID] { sceneCopy := scene result[i] = append(result[i], &sceneCopy) seenScenes[sceneID] = true } } } } } return result, nil } func (s *Scene) SearchScenesWithCount(ctx context.Context, term string, limit int, offset int) (*models.SceneQuery, error) { rows, err := s.queries.SearchScenes(ctx, queries.SearchScenesParams{ Term: &term, Limit: int32(limit), Offset: int32(offset), }) if err != nil { return nil, err } ids := make([]uuid.UUID, len(rows)) for i, row := range rows { ids[i] = row.SceneID } scenePtrs, _ := s.LoadIds(ctx, ids) scenes := make([]models.Scene, 0, len(scenePtrs)) for _, scene := range scenePtrs { if scene != nil { scenes = append(scenes, *scene) } } count := 0 if len(rows) > 0 { count = parseParadeDBCount(rows[0].TotalCount) } return &models.SceneQuery{ SearchResults: &models.SceneSearchResults{ Scenes: scenes, Count: count, }, }, nil } type paradeDBCountResult struct { Value float64 `json:"value"` } func parseParadeDBCount(raw any) int { if raw == nil { return 0 } jsonBytes, err := json.Marshal(raw) if err != nil { return 0 } var result paradeDBCountResult if err := json.Unmarshal(jsonBytes, &result); err != nil { return 0 } return int(result.Value) } func (s *Scene) CountByPerformer(ctx context.Context, performerID uuid.UUID) (int, error) { count, err := s.queries.CountScenesByPerformer(ctx, performerID) if err != nil { return 0, fmt.Errorf("failed to count scenes by performer: %w", err) } return int(count), nil } func (s *Scene) GetPerformers(ctx context.Context, sceneID uuid.UUID) ([]models.PerformerAppearance, error) { performers, err := s.queries.GetScenePerformers(ctx, sceneID) if err != nil { return nil, err } var result []models.PerformerAppearance for _, row := range performers { result = append(result, models.PerformerAppearance{ Performer: converter.PerformerToModelPtr(row.Performer), As: row.As, }) } return result, nil } func (s *Scene) GetTags(ctx context.Context, sceneID uuid.UUID) ([]models.Tag, error) { dbTags, err := s.queries.GetSceneTags(ctx, sceneID) if err != nil { return nil, err } var tags []models.Tag for _, tag := range dbTags { tags = append(tags, converter.TagToModel(tag)) } return tags, nil } func (s *Scene) GetURLs(ctx context.Context, sceneID uuid.UUID) ([]models.URL, error) { urls, err := s.queries.GetSceneURLs(ctx, sceneID) if err != nil { return nil, err } var result []models.URL for _, url := range urls { result = append(result, models.URL{ URL: url.Url, SiteID: url.SiteID, }) } return result, nil } func (s *Scene) GetFingerprints(ctx context.Context, sceneID uuid.UUID) ([]models.Fingerprint, error) { fingerprints, err := s.queries.GetAllSceneFingerprints(ctx, sceneID) if err != nil { return nil, err } var result []models.Fingerprint for _, fp := range fingerprints { result = append(result, models.Fingerprint{ Hash: models.FingerprintHash(fp.Hash), Algorithm: models.FingerprintAlgorithm(fp.Algorithm), Duration: int(fp.Duration), Created: fp.CreatedAt, }) } return result, nil } // Dataloader for fingerprints for multiple scenes func (s *Scene) LoadFingerprints(ctx context.Context, currentUserID uuid.UUID, ids []uuid.UUID, onlySubmitted bool) ([][]models.Fingerprint, []error) { if len(ids) == 0 { return make([][]models.Fingerprint, 0), nil } // Prepare parameters for the query var filterUserID uuid.NullUUID if onlySubmitted { filterUserID = uuid.NullUUID{UUID: currentUserID, Valid: true} } params := queries.GetAllFingerprintsParams{ CurrentUserID: currentUserID, // Always pass for user_submitted/user_reported checks SceneIds: ids, // Scene IDs to query FilterUserID: filterUserID, // Pass user ID when filtering, nil UUID when not } rows, err := s.queries.GetAllFingerprints(ctx, params) if err != nil { return nil, errutil.DuplicateError(err, len(ids)) } // Group results by scene ID m := make(map[uuid.UUID][]models.Fingerprint) for _, row := range rows { // Convert the database row to models.Fingerprint fp := models.Fingerprint{ Hash: models.FingerprintHash(row.Hash), Algorithm: models.FingerprintAlgorithm(row.Algorithm), Duration: row.Duration, Submissions: int(row.Submissions), Reports: int(row.Reports), UserSubmitted: row.UserSubmitted, UserReported: row.UserReported, Created: row.CreatedAt, Updated: row.UpdatedAt, } m[row.SceneID] = append(m[row.SceneID], fp) } // Build result in the same order as input IDs result := make([][]models.Fingerprint, len(ids)) for i, id := range ids { result[i] = m[id] } return result, nil } // Dataloader for performer appearances for multiple scenes func (s *Scene) LoadAppearances(ctx context.Context, ids []uuid.UUID) ([][]models.PerformerScene, []error) { if len(ids) == 0 { return make([][]models.PerformerScene, 0), nil } appearances, err := s.queries.FindSceneAppearancesByIds(ctx, ids) if err != nil { return nil, errutil.DuplicateError(err, len(ids)) } // Group results by scene ID m := make(map[uuid.UUID][]models.PerformerScene) for _, appearance := range appearances { performerScene := models.PerformerScene{ PerformerID: appearance.PerformerID, As: appearance.As, } m[appearance.SceneID] = append(m[appearance.SceneID], performerScene) } // Build result in the same order as input IDs result := make([][]models.PerformerScene, len(ids)) for i, id := range ids { result[i] = m[id] } return result, nil } // Dataloader for URLs for multiple scenes func (s *Scene) LoadURLs(ctx context.Context, ids []uuid.UUID) ([][]models.URL, []error) { if len(ids) == 0 { return make([][]models.URL, 0), nil } urls, err := s.queries.FindSceneUrlsByIds(ctx, ids) if err != nil { return nil, errutil.DuplicateError(err, len(ids)) } // Group results by scene ID m := make(map[uuid.UUID][]models.URL) for _, url := range urls { urlModel := models.URL{ URL: url.Url, SiteID: url.SiteID, } m[url.SceneID] = append(m[url.SceneID], urlModel) } // Build result in the same order as input IDs result := make([][]models.URL, len(ids)) for i, id := range ids { result[i] = m[id] } return result, nil } // Mutations func (s *Scene) Create(ctx context.Context, input models.SceneCreateInput) (*models.Scene, error) { id, err := uuid.NewV7() if err != nil { return nil, err } // Populate a new scene from the input newScene := converter.SceneCreateInputToScene(input) newScene.ID = id var scene models.Scene err = s.withTxn(func(tx *queries.Queries) error { dbScene, err := tx.CreateScene(ctx, converter.SceneToCreateParams(newScene)) if err != nil { return err } scene = converter.SceneToModel(dbScene) // Save the fingerprints if err := createFingerprints(ctx, tx, newScene.ID, input.Fingerprints); err != nil { return err } // save the performers if err := createPerformers(ctx, tx, scene.ID, input.Performers); err != nil { return err } // Save the URLs if err := createURLs(ctx, tx, scene.ID, input.Urls); err != nil { return err } // Save the tags if err := createTags(ctx, tx, scene.ID, input.TagIds); err != nil { return err } // Save the images return createImages(ctx, tx, scene.ID, input.ImageIds) }) return &scene, err } func (s *Scene) Update(ctx context.Context, input models.SceneUpdateInput) (*models.Scene, error) { // Get the existing scene and modify it dbScene, err := s.queries.FindScene(ctx, input.ID) if err != nil { return nil, err } updatedScene := converter.SceneToModel(dbScene) // Populate scene from the input converter.UpdateSceneFromUpdateInput(&updatedScene, input) if err := s.withTxn(func(tx *queries.Queries) error { scene, err := tx.UpdateScene(ctx, converter.SceneToUpdateParams(updatedScene)) if err != nil { return err } // Save the checksums userID := auth.GetCurrentUser(ctx).ID if err := updateFingerprints(ctx, tx, scene.ID, userID, input.Fingerprints); err != nil { return err } if err := updatePerformers(ctx, tx, scene.ID, input.Performers); err != nil { return err } // Save the tags if err := updateTags(ctx, tx, scene.ID, input.TagIds); err != nil { return err } // Save the URLs if err := updateURLs(ctx, tx, scene.ID, input.Urls); err != nil { return err } // Save the images return updateImages(ctx, tx, scene.ID, input.ImageIds) }); err != nil { return nil, err } return &updatedScene, nil } func (s *Scene) Delete(ctx context.Context, id uuid.UUID) error { return s.queries.DeleteScene(ctx, id) } func (s *Scene) SubmitFingerprint(ctx context.Context, input models.FingerprintSubmission) (bool, error) { // Find the scene dbScene, err := s.queries.FindScene(ctx, input.SceneID) if err != nil || dbScene.Deleted { // FIXME: this should error out, but due to the use-case in Stash, // it will stop submitting fingerprints if a single one fails // see https://github.com/stashapp/stash/blob/v0.16.1/pkg/scraper/stashbox/stash_box.go#L254-L257 return true, nil // return false, fmt.Errorf("scene is deleted, unable to submit fingerprint") } // if no user is set, or if the current user does not have the modify // role, then set users to the current user if len(input.Fingerprint.UserIds) == 0 || !auth.IsRole(ctx, models.RoleEnumModify) { currentUserID := auth.GetCurrentUser(ctx).ID input.Fingerprint.UserIds = []uuid.UUID{currentUserID} } // set the default vote vote := models.FingerprintSubmissionTypeValid if input.Vote != nil { vote = *input.Vote } // if the user is reporting a fingerprint, ensure that the fingerprint has at least one submission if vote == models.FingerprintSubmissionTypeInvalid { submissionExists, err := s.queries.SubmittedHashExists(ctx, queries.SubmittedHashExistsParams{ SceneID: input.SceneID, Hash: input.Fingerprint.Hash.Int64(), Algorithm: input.Fingerprint.Algorithm.String(), }) if err != nil { return false, err } if !submissionExists { return false, errors.New("fingerprint has no submissions") } } voteInt := submissionTypeToInt(vote) sceneFingerprint := createSubmittedSceneFingerprints(input.SceneID, []models.FingerprintInput{*input.Fingerprint}, voteInt) // vote == 0 means the user is unmatching the fingerprint // Unmatch is the deprecated field, but we still need to support it unmatch := vote == models.FingerprintSubmissionTypeRemove || (input.Unmatch != nil && *input.Unmatch) if !unmatch { // set the new fingerprints for _, fp := range sceneFingerprint { id, err := getOrCreateFingerprint(ctx, s.queries, fp.Hash, fp.Algorithm) if err != nil { return false, err } if err := s.queries.CreateOrReplaceFingerprint(ctx, queries.CreateOrReplaceFingerprintParams{ FingerprintID: int(id), SceneID: fp.SceneID, UserID: fp.UserID, Duration: fp.Duration, Vote: int16(voteInt), }); err != nil { return false, err } } } else { // remove fingerprints that match the user id, algorithm and hash for _, fp := range sceneFingerprint { if err := s.queries.DeleteSceneFingerprint(ctx, queries.DeleteSceneFingerprintParams{ Hash: fp.Hash.Int64(), Algorithm: fp.Algorithm, UserID: fp.UserID, SceneID: fp.SceneID, }); err != nil { return false, err } } } return true, nil } func (s *Scene) SubmitFingerprints(ctx context.Context, inputs []models.FingerprintBatchSubmission) ([]models.FingerprintSubmissionResult, error) { results := make([]models.FingerprintSubmissionResult, len(inputs)) // Extract unique scene IDs for batch validation sceneIDMap := make(map[uuid.UUID]bool) for _, input := range inputs { sceneIDMap[input.SceneID] = true } sceneIDs := make([]uuid.UUID, 0, len(sceneIDMap)) for sceneID := range sceneIDMap { sceneIDs = append(sceneIDs, sceneID) } // Get current user currentUserID := auth.GetCurrentUser(ctx).ID // Wrap all database operations in a transaction err := s.withTxn(func(tx *queries.Queries) error { // Batch fetch scenes scenes, err := tx.GetScenes(ctx, sceneIDs) if err != nil { return err } // Create map of valid scene IDs (not deleted) sceneExists := make(map[uuid.UUID]bool) for _, scene := range scenes { if !scene.Deleted { sceneExists[scene.ID] = true } } // Collect all valid fingerprints and prepare for batch operations type fingerprintEntry struct { hash models.FingerprintHash algorithm string sceneID uuid.UUID userID uuid.UUID duration int inputIdx int } var validFingerprints []fingerprintEntry // First pass: validate and collect fingerprints for i, input := range inputs { result := models.FingerprintSubmissionResult{ Hash: input.Hash, SceneID: input.SceneID, } // Skip if scene doesn't exist or is deleted if !sceneExists[input.SceneID] { errMsg := "invalid or deleted scene" result.Error = &errMsg results[i] = result continue } // Skip if duration is not valid if input.Duration <= 0 { errMsg := "duration must be greater than 0" result.Error = &errMsg results[i] = result continue } validFingerprints = append(validFingerprints, fingerprintEntry{ hash: input.Hash, algorithm: input.Algorithm.String(), sceneID: input.SceneID, userID: currentUserID, duration: input.Duration, inputIdx: i, }) // Initialize result as success (will be set to error if insert fails) results[i] = result } // If no valid fingerprints, return early if len(validFingerprints) == 0 { return nil } // Insert fingerprints one by one for _, fp := range validFingerprints { fingerprintID, err := getOrCreateFingerprint(ctx, tx, fp.hash, fp.algorithm) if err != nil { errMsg := err.Error() results[fp.inputIdx].Error = &errMsg continue } if err := tx.CreateOrReplaceFingerprint(ctx, queries.CreateOrReplaceFingerprintParams{ FingerprintID: fingerprintID, SceneID: fp.sceneID, UserID: fp.userID, Duration: fp.duration, Vote: 1, }); err != nil { errMsg := err.Error() results[fp.inputIdx].Error = &errMsg } } return nil }) if err != nil { return nil, err } return results, nil } func (s *Scene) MoveFingerprintSubmissions(ctx context.Context, input models.MoveFingerprintSubmissionsInput) error { return s.withTxn(func(txnQueries *queries.Queries) error { // Validate source scene exists and is not deleted sourceScene, err := txnQueries.FindScene(ctx, input.SourceSceneID) if err != nil { return fmt.Errorf("source scene not found: %w", err) } if sourceScene.Deleted { return fmt.Errorf("source scene is deleted") } // Validate target scene exists and is not deleted targetScene, err := txnQueries.FindScene(ctx, input.TargetSceneID) if err != nil { return fmt.Errorf("target scene not found: %w", err) } if targetScene.Deleted { return fmt.Errorf("target scene is deleted") } // Move each fingerprint for _, fp := range input.Fingerprints { rowsAffected, err := txnQueries.MoveSceneFingerprintSubmissions(ctx, queries.MoveSceneFingerprintSubmissionsParams{ Hash: fp.Hash.Int64(), Algorithm: fp.Algorithm.String(), TargetSceneID: input.TargetSceneID, SourceSceneID: input.SourceSceneID, }) if err != nil { return fmt.Errorf("failed to move fingerprint %s (%s): %w", fp.Hash.Hex(), fp.Algorithm, err) } if rowsAffected == 0 { return fmt.Errorf("fingerprint %s (%s) not found on source scene", fp.Hash.Hex(), fp.Algorithm) } } return nil }) } func (s *Scene) DeleteFingerprintSubmissions(ctx context.Context, input models.DeleteFingerprintSubmissionsInput) error { return s.withTxn(func(txnQueries *queries.Queries) error { // Validate scene exists and is not deleted scene, err := txnQueries.FindScene(ctx, input.SceneID) if err != nil { return fmt.Errorf("scene not found: %w", err) } if scene.Deleted { return fmt.Errorf("scene is deleted") } // Delete submissions for each fingerprint for _, fp := range input.Fingerprints { rowsAffected, err := txnQueries.DeleteAllSceneFingerprintSubmissions(ctx, queries.DeleteAllSceneFingerprintSubmissionsParams{ Hash: fp.Hash.Int64(), Algorithm: fp.Algorithm.String(), SceneID: input.SceneID, }) if err != nil { return fmt.Errorf("failed to delete fingerprint submissions %s (%s): %w", fp.Hash.Hex(), fp.Algorithm, err) } if rowsAffected == 0 { return fmt.Errorf("fingerprint %s (%s) not found on scene", fp.Hash.Hex(), fp.Algorithm) } } return nil }) } func (s *Scene) FindExistingScenes(ctx context.Context, input models.QueryExistingSceneInput) ([]models.Scene, error) { var hashes []int64 var studioID uuid.NullUUID if input.StudioID != nil { studioID = uuid.NullUUID{UUID: *input.StudioID, Valid: true} } for _, fp := range input.Fingerprints { hashes = append(hashes, fp.Hash.Int64()) } scenes, err := s.queries.FindExistingScenes(ctx, queries.FindExistingScenesParams{ Hashes: hashes, Title: input.Title, StudioID: studioID, }) return converter.ScenesToModels(scenes), err } func submissionTypeToInt(t models.FingerprintSubmissionType) int { switch t { case models.FingerprintSubmissionTypeValid: return 1 case models.FingerprintSubmissionTypeInvalid: return -1 default: return 0 } } func createSubmittedSceneFingerprints(sceneID uuid.UUID, fingerprints []models.FingerprintInput, vote int) []models.SceneFingerprint { var ret []models.SceneFingerprint for _, fingerprint := range fingerprints { if fingerprint.Duration > 0 { for _, userID := range fingerprint.UserIds { ret = append(ret, models.SceneFingerprint{ SceneID: sceneID, UserID: userID, Hash: fingerprint.Hash, Algorithm: fingerprint.Algorithm.String(), Duration: fingerprint.Duration, Vote: vote, }) } } } return ret } func createFingerprints(ctx context.Context, tx *queries.Queries, sceneID uuid.UUID, fingerprints []models.FingerprintEditInput) error { var params []queries.CreateSceneFingerprintsParams user := auth.GetCurrentUser(ctx) for _, fp := range fingerprints { id, err := getOrCreateFingerprint(ctx, tx, fp.Hash, fp.Algorithm.String()) if err != nil { return err } // if no user is set, or if the current user does not have the modify // role, then set users to the current user userIDs := fp.UserIds if len(userIDs) == 0 || !auth.IsRole(ctx, models.RoleEnumModify) { userIDs = []uuid.UUID{user.ID} } for _, userID := range userIDs { params = append(params, queries.CreateSceneFingerprintsParams{ UserID: userID, SceneID: sceneID, FingerprintID: int(id), Duration: fp.Duration, }) } } _, err := tx.CreateSceneFingerprints(ctx, params) return err } func updateFingerprints(ctx context.Context, tx *queries.Queries, sceneID uuid.UUID, userID uuid.UUID, fingerprints []models.FingerprintEditInput) error { if err := tx.DeleteSceneFingerprintsByScene(ctx, sceneID); err != nil { return err } dbFingerprints, err := tx.GetAllSceneFingerprints(ctx, sceneID) if err != nil && !errors.Is(err, pgx.ErrNoRows) { return err } var existingFingerprints []models.SceneFingerprint for _, fp := range dbFingerprints { existingFingerprints = append(existingFingerprints, models.SceneFingerprint{ SceneID: sceneID, UserID: fp.UserID, Hash: models.FingerprintHash(fp.Hash), Algorithm: fp.Algorithm, Duration: int(fp.Duration), CreatedAt: fp.CreatedAt, }) } user := auth.GetCurrentUser(ctx) sceneFingerprints := createUpdatedSceneFingerprints(sceneID, existingFingerprints, fingerprints, user.ID) var params []queries.CreateSceneFingerprintsParams for _, fp := range sceneFingerprints { id, err := getOrCreateFingerprint(ctx, tx, fp.Hash, fp.Algorithm) if err != nil { return err } params = append(params, queries.CreateSceneFingerprintsParams{ UserID: fp.UserID, SceneID: sceneID, FingerprintID: int(id), Duration: fp.Duration, }) } _, err = tx.CreateSceneFingerprints(ctx, params) return err } func createPerformers(ctx context.Context, tx *queries.Queries, sceneID uuid.UUID, performers []models.PerformerAppearanceInput) error { var params []queries.CreateScenePerformersParams for _, performer := range performers { param := queries.CreateScenePerformersParams{ SceneID: sceneID, PerformerID: performer.PerformerID, As: performer.As, } params = append(params, param) } _, err := tx.CreateScenePerformers(ctx, params) return err } func updatePerformers(ctx context.Context, tx *queries.Queries, sceneID uuid.UUID, performers []models.PerformerAppearanceInput) error { if err := tx.DeleteScenePerformers(ctx, sceneID); err != nil { return err } return createPerformers(ctx, tx, sceneID, performers) } func createURLs(ctx context.Context, tx *queries.Queries, sceneID uuid.UUID, urls []models.URL) error { var params []queries.CreateSceneURLsParams for _, url := range urls { params = append(params, queries.CreateSceneURLsParams{ SceneID: sceneID, Url: url.URL, SiteID: url.SiteID, }) } _, err := tx.CreateSceneURLs(ctx, params) return err } func updateURLs(ctx context.Context, tx *queries.Queries, sceneID uuid.UUID, urls []models.URL) error { if err := tx.DeleteSceneURLs(ctx, sceneID); err != nil { return err } return createURLs(ctx, tx, sceneID, urls) } func createImages(ctx context.Context, tx *queries.Queries, sceneID uuid.UUID, images []uuid.UUID) error { var params []queries.CreateSceneImagesParams for _, image := range images { params = append(params, queries.CreateSceneImagesParams{ SceneID: sceneID, ImageID: image, }) } _, err := tx.CreateSceneImages(ctx, params) return err } func updateImages(ctx context.Context, tx *queries.Queries, sceneID uuid.UUID, images []uuid.UUID) error { // TODO Remove unused images if err := tx.DeleteSceneImages(ctx, sceneID); err != nil { return err } return createImages(ctx, tx, sceneID, images) } func createTags(ctx context.Context, tx *queries.Queries, sceneID uuid.UUID, tags []uuid.UUID) error { var params []queries.CreateSceneTagsParams for _, tag := range tags { params = append(params, queries.CreateSceneTagsParams{ SceneID: sceneID, TagID: tag, }) } _, err := tx.CreateSceneTags(ctx, params) return err } func updateTags(ctx context.Context, tx *queries.Queries, sceneID uuid.UUID, tags []uuid.UUID) error { if err := tx.DeleteSceneTagsByScene(ctx, sceneID); err != nil { return err } return createTags(ctx, tx, sceneID, tags) } func createUpdatedSceneFingerprints(sceneID uuid.UUID, original []models.SceneFingerprint, updated []models.FingerprintEditInput, currentUserID uuid.UUID) []models.SceneFingerprint { var ret []models.SceneFingerprint // hashes present are kept - use existing users // hashes missing are destroyed for _, o := range original { for _, u := range updated { if isSameHash(o, u) { ret = append(ret, o) break } } } // new hashes are created and assigned to the current user for _, u := range updated { found := false for _, o := range original { if isSameHash(o, u) { found = true break } } if !found { if len(u.UserIds) == 0 { u.UserIds = []uuid.UUID{currentUserID} } if u.Duration > 0 { for _, userID := range u.UserIds { ret = append(ret, models.SceneFingerprint{ SceneID: sceneID, UserID: userID, Hash: u.Hash, Algorithm: u.Algorithm.String(), Duration: u.Duration, CreatedAt: u.Created, }) } } } } return ret } func getOrCreateFingerprint(ctx context.Context, tx *queries.Queries, hash models.FingerprintHash, algorithm string) (int, error) { // Try to get FP dbFP, err := tx.GetFingerprint(ctx, queries.GetFingerprintParams{ Hash: hash.Int64(), Algorithm: algorithm, }) if err != nil { // If err, try to create FP instead dbFP, err = tx.CreateFingerprint(ctx, queries.CreateFingerprintParams{ Hash: hash.Int64(), Algorithm: algorithm, }) } return dbFP.ID, err } func isSameHash(f models.SceneFingerprint, ff models.FingerprintEditInput) bool { return f.Algorithm == ff.Algorithm.String() && f.Hash == ff.Hash } func (s *Scene) LoadIds(ctx context.Context, ids []uuid.UUID) ([]*models.Scene, []error) { scenes, err := s.queries.GetScenes(ctx, ids) if err != nil { return nil, errutil.DuplicateError(err, len(ids)) } result := make([]*models.Scene, len(ids)) sceneMap := make(map[uuid.UUID]*models.Scene) for _, scene := range scenes { sceneMap[scene.ID] = converter.SceneToModelPtr(scene) } for i, id := range ids { result[i] = sceneMap[id] } return result, make([]error, len(ids)) } ================================================ FILE: internal/service/site/query.go ================================================ package site import ( "context" sq "github.com/Masterminds/squirrel" "github.com/stashapp/stash-box/internal/converter" "github.com/stashapp/stash-box/internal/models" queryhelper "github.com/stashapp/stash-box/internal/service/query" ) func (s *Site) Query(ctx context.Context) ([]models.Site, int, error) { psql := sq.StatementBuilder.PlaceholderFormat(sq.Dollar) query := psql.Select("*").From("sites").OrderBy("name ASC") // Get count countQuery := psql.Select("COUNT(*)").From("sites") count, err := queryhelper.ExecuteCount(ctx, countQuery, s.queries.DB(), "QuerySitesCount") if err != nil { return nil, 0, err } // Execute query sites, err := queryhelper.ExecuteQuery(ctx, query, s.queries.DB(), converter.SiteToModel, "QuerySites") if err != nil { return nil, 0, err } return sites, count, nil } ================================================ FILE: internal/service/site/service.go ================================================ package site import ( "context" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/converter" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/internal/queries" "github.com/stashapp/stash-box/internal/service/errutil" ) // Site handles site-related operations type Site struct { queries *queries.Queries withTxn queries.WithTxnFunc } // NewSite creates a new site service func NewSite(queries *queries.Queries, withTxn queries.WithTxnFunc) *Site { return &Site{ queries: queries, withTxn: withTxn, } } // WithTxn executes a function within a transaction func (s *Site) WithTxn(fn func(*queries.Queries) error) error { return s.withTxn(fn) } // Create creates a new site func (s *Site) Create(ctx context.Context, input models.SiteCreateInput) (*models.Site, error) { id, err := uuid.NewV7() if err != nil { return nil, err } newSite := converter.SiteCreateInputToSite(input) newSite.ID = id var site *models.Site err = s.withTxn(func(tx *queries.Queries) error { dbSite, err := tx.CreateSite(ctx, converter.SiteToCreateParams(newSite)) site = converter.SiteToModelPtr(dbSite) return err }) return site, err } // Update updates an existing site func (s *Site) Update(ctx context.Context, input models.SiteUpdateInput) (*models.Site, error) { var site *models.Site err := s.withTxn(func(tx *queries.Queries) error { dbSite, err := tx.GetSite(ctx, input.ID) if err != nil { return err } updatedSite := converter.SiteToModel(dbSite) converter.UpdateSiteFromUpdateInput(&updatedSite, input) dbSite, err = tx.UpdateSite(ctx, converter.SiteToUpdateParams(updatedSite)) site = converter.SiteToModelPtr(dbSite) return err }) return site, err } // Destroy deletes a site by ID func (s *Site) Destroy(ctx context.Context, id uuid.UUID) error { return s.queries.DeleteSite(ctx, id) } // Find finds a site by ID func (s *Site) GetByID(ctx context.Context, id uuid.UUID) (*models.Site, error) { site, err := s.queries.GetSite(ctx, id) if err != nil { return nil, errutil.IgnoreNotFound(err) } return converter.SiteToModelPtr(site), nil } // Dataloader methods func (s *Site) LoadIds(ctx context.Context, ids []uuid.UUID) ([]*models.Site, []error) { sites, err := s.queries.FindSitesByIds(ctx, ids) if err != nil { return nil, errutil.DuplicateError(err, len(ids)) } result := make([]*models.Site, len(ids)) siteMap := make(map[uuid.UUID]*models.Site) for _, site := range sites { siteMap[site.ID] = converter.SiteToModelPtr(site) } for i, id := range ids { result[i] = siteMap[id] } return result, make([]error, len(ids)) } ================================================ FILE: internal/service/studio/query.go ================================================ package studio import ( "context" "fmt" "strings" sq "github.com/Masterminds/squirrel" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/auth" "github.com/stashapp/stash-box/internal/converter" "github.com/stashapp/stash-box/internal/models" queryhelper "github.com/stashapp/stash-box/internal/service/query" ) func (s *Studio) Query(ctx context.Context, input models.StudioQueryInput) (*models.QueryStudiosResultType, error) { user := auth.GetCurrentUser(ctx) psql := sq.StatementBuilder.PlaceholderFormat(sq.Dollar) // Build data query query := s.buildStudioQuery(psql, input, user.ID, false) // Apply sort query = queryhelper.ApplySortParams(query, "studios", input.Sort, input.Direction, "name", "ASC") // Apply pagination query = queryhelper.ApplyPagination(query, input.Page, input.PerPage) // Get count countQuery := s.buildStudioQuery(psql, input, user.ID, true) count, err := queryhelper.ExecuteCount(ctx, countQuery, s.queries.DB(), "QueryStudiosCount") if err != nil { return nil, err } // Execute query studios, err := queryhelper.ExecuteQuery(ctx, query, s.queries.DB(), converter.StudioToModel, "QueryStudios") if err != nil { return nil, err } return &models.QueryStudiosResultType{ Count: count, Studios: studios, }, nil } func (s *Studio) buildStudioQuery(psql sq.StatementBuilderType, input models.StudioQueryInput, userID uuid.UUID, forCount bool) sq.SelectBuilder { var query sq.SelectBuilder if forCount { query = psql.Select("COUNT(DISTINCT studios.id)").From("studios") } else { query = psql.Select("studios.*").From("studios") } query = query. LeftJoin("studios as parent_studio ON studios.parent_studio_id = parent_studio.id"). Where(sq.Eq{"studios.deleted": false}) // Filter by URL if input.URL != nil && *input.URL != "" { query = query. Join("studio_urls ON studios.id = studio_urls.studio_id"). Where(sq.Eq{"studio_urls.url": *input.URL}) } // Filter by name only if input.Name != nil && *input.Name != "" { searchTerm := "%" + *input.Name + "%" query = query.Where(sq.ILike{"studios.name": searchTerm}) } // Filter by names (searches studio name, parent name, and aliases) if input.Names != nil && *input.Names != "" { searchTerm := "%" + *input.Names + "%" existsClause := fmt.Sprintf( "EXISTS (SELECT S.id FROM studios S LEFT JOIN studio_aliases SA ON S.id = SA.studio_id WHERE studios.id = S.id AND (LOWER(S.name) LIKE %s OR LOWER(SA.alias) LIKE %s) GROUP BY S.id)", sq.Placeholders(1), sq.Placeholders(1), ) orConditions := sq.Or{ sq.ILike{"studios.name": searchTerm}, sq.ILike{"parent_studio.name": searchTerm}, sq.Expr(existsClause, strings.ToLower(searchTerm), strings.ToLower(searchTerm)), } query = query.Where(orConditions) } // Filter by has parent if input.HasParent != nil { if *input.HasParent { query = query.Where("parent_studio.id IS NOT NULL") } else { query = query.Where("parent_studio.id IS NULL") } } // Filter by parent ID if input.Parent != nil { query = queryhelper.ApplyIDCriterion(query, "studios.parent_studio_id", input.Parent) } // Filter by favorite status if input.IsFavorite != nil { if *input.IsFavorite { query = query. Join("studio_favorites F ON studios.id = F.studio_id"). Where(sq.Eq{"F.user_id": userID}) } else { query = query. LeftJoin("studio_favorites F ON studios.id = F.studio_id AND F.user_id = ?", userID). Where("F.studio_id IS NULL") } } return query } ================================================ FILE: internal/service/studio/service.go ================================================ package studio import ( "context" "fmt" "strings" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/auth" "github.com/stashapp/stash-box/internal/converter" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/internal/queries" "github.com/stashapp/stash-box/internal/service/errutil" ) // Studio handles studio-related operations type Studio struct { queries *queries.Queries withTxn queries.WithTxnFunc } // NewStudio creates a new studio service func NewStudio(queries *queries.Queries, withTxn queries.WithTxnFunc) *Studio { return &Studio{ queries: queries, withTxn: withTxn, } } // WithTxn executes a function within a transaction func (s *Studio) WithTxn(fn func(*queries.Queries) error) error { return s.withTxn(fn) } // Queries func (s *Studio) FindByID(ctx context.Context, id uuid.UUID) (*models.Studio, error) { studio, err := s.queries.FindStudio(ctx, id) if err != nil { return nil, errutil.IgnoreNotFound(err) } return converter.StudioToModelPtr(studio), nil } func (s *Studio) FindByName(ctx context.Context, name string) (*models.Studio, error) { studio, err := s.queries.FindStudioByName(ctx, strings.ToUpper(name)) if err != nil { return nil, errutil.IgnoreNotFound(err) } return converter.StudioToModelPtr(studio), nil } func (s *Studio) FindByAlias(ctx context.Context, alias string) (*models.Studio, error) { studio, err := s.queries.FindStudioByAlias(ctx, strings.ToUpper(alias)) if err != nil { return nil, errutil.IgnoreNotFound(err) } return converter.StudioToModelPtr(studio), nil } func (s *Studio) FindByParentID(ctx context.Context, parentID uuid.UUID) ([]models.Studio, error) { studios, err := s.queries.GetChildStudios(ctx, uuid.NullUUID{UUID: parentID, Valid: !parentID.IsNil()}) if err != nil { return nil, err } return converter.StudiosToModels(studios), nil } func (s *Studio) CountByPerformer(ctx context.Context, performerID uuid.UUID, studioID *uuid.UUID) ([]models.PerformerStudio, error) { var result []models.PerformerStudio if studioID != nil { // Filter to studios in the network (the studio, its parent, and children) rows, err := s.queries.GetStudiosByPerformerAndNetwork(ctx, queries.GetStudiosByPerformerAndNetworkParams{ PerformerID: performerID, StudioID: *studioID, }) if err != nil { return nil, fmt.Errorf("failed to get studios by performer and network: %w", err) } for _, row := range rows { performerStudio := models.PerformerStudio{ Studio: converter.StudioToModelPtr(row.Studio), SceneCount: int(row.SceneCount), } result = append(result, performerStudio) } } else { // Return all studios rows, err := s.queries.GetStudiosByPerformer(ctx, performerID) if err != nil { return nil, fmt.Errorf("failed to get studios by performer: %w", err) } for _, row := range rows { performerStudio := models.PerformerStudio{ Studio: converter.StudioToModelPtr(row.Studio), SceneCount: int(row.SceneCount), } result = append(result, performerStudio) } } return result, nil } func (s *Studio) GetChildren(ctx context.Context, studioID uuid.UUID) ([]models.Studio, error) { children, err := s.queries.GetChildStudios(ctx, uuid.NullUUID{UUID: studioID, Valid: !studioID.IsNil()}) if err != nil { return nil, err } return converter.StudiosToModels(children), nil } func (s *Studio) GetAliases(ctx context.Context, studioID uuid.UUID) ([]string, error) { return s.queries.GetStudioAliases(ctx, studioID) } func (s *Studio) GetURLs(ctx context.Context, studioID uuid.UUID) ([]models.URL, error) { urls, err := s.queries.GetStudioURLs(ctx, studioID) if err != nil { return nil, err } var result []models.URL for _, url := range urls { result = append(result, models.URL{ URL: url.Url, SiteID: url.SiteID, }) } return result, nil } // Mutations func (s *Studio) Create(ctx context.Context, input models.StudioCreateInput) (*models.Studio, error) { // Populate a new studio from the input newStudio, err := converter.StudioCreateInputToCreateParams(input) if err != nil { return nil, err } var studio *models.Studio err = s.withTxn(func(tx *queries.Queries) error { var err error dbStudio, err := tx.CreateStudio(ctx, newStudio) if err != nil { return err } studio = converter.StudioToModelPtr(dbStudio) // Save the aliases if err := createAliases(ctx, tx, studio.ID, input.Aliases); err != nil { return err } // Save the URLs if err := createURLs(ctx, tx, studio.ID, input.Urls); err != nil { return err } // Save the images return createImages(ctx, tx, studio.ID, input.ImageIds) }) return studio, err } func (s *Studio) Update(ctx context.Context, input models.StudioUpdateInput) (*models.Studio, error) { var studio *models.Studio err := s.withTxn(func(tx *queries.Queries) error { // Get the existing studio and modify it existingStudio, err := tx.FindStudio(ctx, input.ID) if err != nil { return err } // Populate studio from the input params := converter.UpdateStudioFromUpdateInput(existingStudio, input) dbStudio, err := tx.UpdateStudio(ctx, params) if err != nil { return err } studio = converter.StudioToModelPtr(dbStudio) // TODO: only do this if provided // Save the aliases if err := updateAliases(ctx, tx, studio.ID, input.Aliases); err != nil { return err } // Save the URLs if err := updateURLs(ctx, tx, studio.ID, input.Urls); err != nil { return err } // Save the images return updateImages(ctx, tx, studio.ID, input.ImageIds) }) return studio, err } func (s *Studio) Delete(ctx context.Context, id uuid.UUID) error { return s.withTxn(func(tx *queries.Queries) error { // references have on delete cascade, so shouldn't be necessary // to remove them explicitly return tx.DeleteStudio(ctx, id) }) } func (s *Studio) Favorite(ctx context.Context, id uuid.UUID, favorite bool) error { currentUser := auth.GetCurrentUser(ctx) return s.withTxn(func(tx *queries.Queries) error { studio, err := tx.FindStudio(ctx, id) if err != nil { return err } if studio.Deleted { return fmt.Errorf("studio is deleted, unable to make favorite") } if favorite { return tx.CreateStudioFavorite(ctx, queries.CreateStudioFavoriteParams{ StudioID: studio.ID, UserID: currentUser.ID, }) } return tx.DeleteStudioFavorite(ctx, queries.DeleteStudioFavoriteParams{ StudioID: studio.ID, UserID: currentUser.ID, }) }) } func (s *Studio) Search(ctx context.Context, term string, limit int) ([]models.Studio, error) { rows, err := s.queries.SearchStudios(ctx, queries.SearchStudiosParams{ Term: &term, Limit: int32(limit), }) if err != nil { return nil, err } // Extract studio IDs ids := make([]uuid.UUID, len(rows)) for i, row := range rows { ids[i] = row.StudioID } // Load full studios studioPtrs, _ := s.LoadIds(ctx, ids) studios := make([]models.Studio, 0, len(studioPtrs)) for _, studio := range studioPtrs { if studio != nil { studios = append(studios, *studio) } } return studios, nil } func createAliases(ctx context.Context, tx *queries.Queries, studioID uuid.UUID, aliases []string) error { var params []queries.CreateStudioAliasesParams for _, alias := range aliases { params = append(params, queries.CreateStudioAliasesParams{ StudioID: studioID, Alias: alias, }) } _, err := tx.CreateStudioAliases(ctx, params) return err } func updateAliases(ctx context.Context, tx *queries.Queries, studioID uuid.UUID, aliases []string) error { if err := tx.DeleteStudioAliases(ctx, studioID); err != nil { return err } return createAliases(ctx, tx, studioID, aliases) } func createURLs(ctx context.Context, tx *queries.Queries, studioID uuid.UUID, urls []models.URL) error { var params []queries.CreateStudioURLsParams for _, url := range urls { params = append(params, queries.CreateStudioURLsParams{ StudioID: studioID, Url: url.URL, SiteID: url.SiteID, }) } _, err := tx.CreateStudioURLs(ctx, params) return err } func updateURLs(ctx context.Context, tx *queries.Queries, studioID uuid.UUID, urls []models.URL) error { if err := tx.DeleteStudioURLs(ctx, studioID); err != nil { return err } return createURLs(ctx, tx, studioID, urls) } func createImages(ctx context.Context, tx *queries.Queries, studioID uuid.UUID, images []uuid.UUID) error { var params []queries.CreateStudioImagesParams for _, image := range images { params = append(params, queries.CreateStudioImagesParams{ StudioID: studioID, ImageID: image, }) } _, err := tx.CreateStudioImages(ctx, params) return err } func updateImages(ctx context.Context, tx *queries.Queries, studioID uuid.UUID, images []uuid.UUID) error { // TODO Remove unused images if err := tx.DeleteStudioImages(ctx, studioID); err != nil { return err } return createImages(ctx, tx, studioID, images) } // Dataloader methods func (s *Studio) LoadIds(ctx context.Context, ids []uuid.UUID) ([]*models.Studio, []error) { studios, err := s.queries.GetStudios(ctx, ids) if err != nil { return nil, errutil.DuplicateError(err, len(ids)) } result := make([]*models.Studio, len(ids)) studioMap := make(map[uuid.UUID]*models.Studio) for _, studio := range studios { studioMap[studio.ID] = converter.StudioToModelPtr(studio) } for i, id := range ids { result[i] = studioMap[id] } return result, make([]error, len(ids)) } // Dataloader for urls for multiple scenes func (s *Studio) LoadURLs(ctx context.Context, ids []uuid.UUID) ([][]models.URL, []error) { urls, err := s.queries.FindStudioUrlsByIds(ctx, ids) if err != nil { return nil, errutil.DuplicateError(err, len(ids)) } result := make([][]models.URL, len(ids)) urlMap := make(map[uuid.UUID][]models.URL) for _, url := range urls { urlMap[url.StudioID] = append(urlMap[url.StudioID], models.URL{ URL: url.Url, SiteID: url.SiteID, }) } for i, id := range ids { result[i] = urlMap[id] } return result, make([]error, len(ids)) } func (s *Studio) LoadAliases(ctx context.Context, ids []uuid.UUID) ([][]string, []error) { aliases, err := s.queries.FindStudioAliasesByIds(ctx, ids) if err != nil { return nil, errutil.DuplicateError(err, len(ids)) } result := make([][]string, len(ids)) aliasMap := make(map[uuid.UUID][]string) for _, alias := range aliases { aliasMap[alias.StudioID] = append(aliasMap[alias.StudioID], alias.Alias) } for i, id := range ids { result[i] = aliasMap[id] } return result, make([]error, len(ids)) } func (s *Studio) LoadIsFavorite(ctx context.Context, userID uuid.UUID, ids []uuid.UUID) ([]bool, []error) { favorites, err := s.queries.FindStudioFavoritesByIds(ctx, queries.FindStudioFavoritesByIdsParams{ StudioIds: ids, UserID: userID, }) if err != nil { return nil, errutil.DuplicateError(err, len(ids)) } result := make([]bool, len(ids)) favoriteMap := make(map[uuid.UUID]bool) for _, favorite := range favorites { favoriteMap[favorite.StudioID] = favorite.IsFavorite } for i, id := range ids { result[i] = favoriteMap[id] } return result, make([]error, len(ids)) } ================================================ FILE: internal/service/tag/query.go ================================================ package tag import ( "context" "fmt" "strings" sq "github.com/Masterminds/squirrel" "github.com/stashapp/stash-box/internal/converter" "github.com/stashapp/stash-box/internal/models" queryhelper "github.com/stashapp/stash-box/internal/service/query" ) func (s *Tag) Query(ctx context.Context, input models.TagQueryInput) (*models.QueryTagsResultType, error) { psql := sq.StatementBuilder.PlaceholderFormat(sq.Dollar) query := psql.Select("tags.*").From("tags").Where(sq.Eq{"deleted": false}) // Filter by name only if input.Name != nil && *input.Name != "" { searchTerm := "%" + *input.Name + "%" query = query.Where(sq.ILike{"tags.name": searchTerm}) } // Filter by names (searches name and aliases) if input.Names != nil && *input.Names != "" { searchTerm := "%" + *input.Names + "%" existsClause := fmt.Sprintf( "EXISTS (SELECT T.id FROM tags T LEFT JOIN tag_aliases TA ON T.id = TA.tag_id WHERE tags.id = T.id AND (LOWER(T.name) LIKE %s OR LOWER(TA.alias) LIKE %s) GROUP BY T.id)", sq.Placeholders(1), sq.Placeholders(1), ) query = query.Where(sq.Expr(existsClause, strings.ToLower(searchTerm), strings.ToLower(searchTerm))) } // Filter by category ID if input.CategoryID != nil { query = query.Where(sq.Eq{"tags.category_id": input.CategoryID}) } // Get count countQuery := psql.Select("COUNT(*)").FromSelect(query, "subquery") count, err := queryhelper.ExecuteCount(ctx, countQuery, s.queries.DB(), "QueryTagsCount") if err != nil { return nil, err } // Apply sort query = queryhelper.ApplySortParams(query, "", input.Sort, input.Direction, "name", "ASC") // Apply pagination query = queryhelper.ApplyPagination(query, input.Page, input.PerPage) // Execute query tags, err := queryhelper.ExecuteQuery(ctx, query, s.queries.DB(), converter.TagToModel, "QueryTags") if err != nil { return nil, err } return &models.QueryTagsResultType{ Count: count, Tags: tags, }, nil } ================================================ FILE: internal/service/tag/service.go ================================================ package tag import ( "context" "strings" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/converter" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/internal/queries" "github.com/stashapp/stash-box/internal/service/errutil" ) // Service handles tag-related operations type Tag struct { queries *queries.Queries withTxn queries.WithTxnFunc } // NewTag creates a new tag service func NewTag(queries *queries.Queries, withTxn queries.WithTxnFunc) *Tag { return &Tag{ queries: queries, withTxn: withTxn, } } // WithTxn executes a function within a transaction func (s *Tag) WithTxn(fn func(*queries.Queries) error) error { return s.withTxn(fn) } // Queries func (s *Tag) FindByID(ctx context.Context, id uuid.UUID) (*models.Tag, error) { tag, err := s.queries.FindTag(ctx, id) if err != nil { return nil, errutil.IgnoreNotFound(err) } return converter.TagToModelPtr(tag), nil } // Find is an alias for FindByID to match repository interface func (s *Tag) Find(ctx context.Context, id uuid.UUID) (*models.Tag, error) { return s.FindByID(ctx, id) } func (s *Tag) FindByName(ctx context.Context, name string) (*models.Tag, error) { tag, err := s.queries.FindTagByName(ctx, strings.ToUpper(name)) if err != nil { return nil, errutil.IgnoreNotFound(err) } return converter.TagToModelPtr(tag), nil } func (s *Tag) FindByAlias(ctx context.Context, alias string) (*models.Tag, error) { tag, err := s.queries.FindTagByAlias(ctx, strings.ToUpper(alias)) if err != nil { return nil, errutil.IgnoreNotFound(err) } return converter.TagToModelPtr(tag), nil } // FindByNameOrAlias attempts to find a tag by name first, then by alias func (s *Tag) FindByNameOrAlias(ctx context.Context, name string) (*models.Tag, error) { // Try to find by name first tag, err := s.FindByName(ctx, name) if err != nil { return nil, err } if tag != nil { return tag, nil } // If not found by name, try by alias tag, err = s.FindByAlias(ctx, name) if err != nil { return nil, err } return tag, nil } func (s *Tag) FindCategory(ctx context.Context, id uuid.UUID) (*models.TagCategory, error) { category, err := s.queries.FindTagCategory(ctx, id) if err != nil { return nil, errutil.IgnoreNotFound(err) } return converter.TagCategoryToModelPtr(category), nil } // FindIdsBySceneIds returns tag IDs for multiple scene IDs, used by dataloader func (s *Tag) FindIdsBySceneIds(ctx context.Context, ids []uuid.UUID) ([][]uuid.UUID, []error) { if len(ids) == 0 { return make([][]uuid.UUID, 0), nil } sceneTags, err := s.queries.FindTagIdsBySceneIds(ctx, ids) if err != nil { return nil, errutil.DuplicateError(err, len(ids)) } // Group results by scene ID m := make(map[uuid.UUID][]uuid.UUID) for _, st := range sceneTags { m[st.SceneID] = append(m[st.SceneID], st.TagID) } // Build result in the same order as input IDs result := make([][]uuid.UUID, len(ids)) for i, id := range ids { result[i] = m[id] } return result, nil } func (s *Tag) GetAliases(ctx context.Context, tagID uuid.UUID) ([]string, error) { return s.queries.GetTagAliases(ctx, tagID) } // Mutations func (s *Tag) Create(ctx context.Context, input models.TagCreateInput) (*models.Tag, error) { var tag queries.Tag err := s.withTxn(func(tx *queries.Queries) error { params, err := converter.TagCreateInputToCreateParams(input) if err != nil { return err } tag, err = tx.CreateTag(ctx, params) if err != nil { return err } return createAliases(ctx, tx, tag.ID, input.Aliases) }) return converter.TagToModelPtr(tag), err } func (s *Tag) Update(ctx context.Context, input models.TagUpdateInput) (*models.Tag, error) { var tag queries.Tag err := s.withTxn(func(tx *queries.Queries) error { existingTag, err := tx.FindTag(ctx, input.ID) if err != nil { return err } params := converter.UpdateTagFromUpdateInput(existingTag, input) tag, err = tx.UpdateTag(ctx, params) if err != nil { return err } return updateAliases(ctx, tx, tag.ID, input.Aliases) }) return converter.TagToModelPtr(tag), err } func (s *Tag) Delete(ctx context.Context, input models.TagDestroyInput) error { return s.withTxn(func(tx *queries.Queries) error { return tx.DeleteTag(ctx, input.ID) }) } func (s *Tag) CreateCategory(ctx context.Context, input models.TagCategoryCreateInput) (*models.TagCategory, error) { params, err := converter.TagCategoryCreateInputToCreateParams(input) if err != nil { return nil, err } var category queries.TagCategory err = s.withTxn(func(tx *queries.Queries) error { category, err = tx.CreateTagCategory(ctx, params) return err }) return converter.TagCategoryToModelPtr(category), err } func (s *Tag) UpdateCategory(ctx context.Context, input models.TagCategoryUpdateInput) (*models.TagCategory, error) { var category queries.TagCategory err := s.withTxn(func(tx *queries.Queries) error { existingCategory, err := tx.FindTagCategory(ctx, input.ID) if err != nil { return err } updatedCategory := converter.UpdateTagCategoryFromUpdateInput(existingCategory, input) category, err = tx.UpdateTagCategory(ctx, updatedCategory) return err }) return converter.TagCategoryToModelPtr(category), err } func (s *Tag) DeleteCategory(ctx context.Context, input models.TagCategoryDestroyInput) error { return s.withTxn(func(tx *queries.Queries) error { return tx.DeleteTagCategory(ctx, input.ID) }) } func (s *Tag) QueryCategories(ctx context.Context) (int, []models.TagCategory, error) { categories, err := s.queries.GetAllTagCategories(ctx) return len(categories), converter.TagCategoriesToModels(categories), err } func (s *Tag) SearchTags(ctx context.Context, term string, limit int) ([]models.Tag, error) { tags, err := s.queries.SearchTags(ctx, queries.SearchTagsParams{ Term: &term, Limit: int32(limit), }) return converter.TagsToModels(tags), err } func createAliases(ctx context.Context, tx *queries.Queries, tagID uuid.UUID, aliases []string) error { var params []queries.CreateTagAliasesParams for _, alias := range aliases { params = append(params, queries.CreateTagAliasesParams{ TagID: tagID, Alias: alias, }) } _, err := tx.CreateTagAliases(ctx, params) return err } func updateAliases(ctx context.Context, tx *queries.Queries, tagID uuid.UUID, aliases []string) error { if err := tx.DeleteTagAliases(ctx, tagID); err != nil { return err } return createAliases(ctx, tx, tagID, aliases) } // Dataloader methods func (s *Tag) LoadIds(ctx context.Context, ids []uuid.UUID) ([]*models.Tag, []error) { tags, err := s.queries.FindTagsByIds(ctx, ids) if err != nil { return nil, errutil.DuplicateError(err, len(ids)) } result := make([]*models.Tag, len(ids)) tagMap := make(map[uuid.UUID]*models.Tag) for _, tag := range tags { tagMap[tag.ID] = converter.TagToModelPtr(tag) } for i, id := range ids { result[i] = tagMap[id] } return result, make([]error, len(ids)) } func (s *Tag) LoadCategoriesByIds(ctx context.Context, ids []uuid.UUID) ([]*models.TagCategory, []error) { categories, err := s.queries.GetTagCategoriesByIds(ctx, ids) if err != nil { return nil, errutil.DuplicateError(err, len(ids)) } result := make([]*models.TagCategory, len(ids)) categoryMap := make(map[uuid.UUID]*models.TagCategory) for _, category := range categories { categoryMap[category.ID] = converter.TagCategoryToModelPtr(category) } for i, id := range ids { result[i] = categoryMap[id] } return result, make([]error, len(ids)) } ================================================ FILE: internal/service/user/activation.go ================================================ package user import ( "context" "errors" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/converter" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/internal/queries" "github.com/stashapp/stash-box/pkg/utils" ) var ErrInvalidActivationKey = errors.New("invalid activation key") func generateActivationKey(ctx context.Context, tx *queries.Queries, emailAddr string, inviteKey *uuid.UUID) (queries.UserToken, error) { data := models.NewUserTokenData{ Email: emailAddr, InviteKey: inviteKey, } param, err := converter.CreateUserTokenParamsFromData(models.UserTokenTypeNewUser, data) if err != nil { return queries.UserToken{}, err } return tx.CreateUserToken(ctx, param) } func generateResetPasswordActivationKey(ctx context.Context, tx *queries.Queries, userID uuid.UUID) (*uuid.UUID, error) { data := models.UserTokenData{ UserID: userID, } param, err := converter.CreateUserTokenParamsFromData(models.UserTokenTypeResetPassword, data) if err != nil { return nil, err } obj, err := tx.CreateUserToken(ctx, param) if err != nil { return nil, err } return &obj.ID, nil } func activateResetPassword(ctx context.Context, tx *queries.Queries, id uuid.UUID, newPassword string) error { token, err := tx.FindUserToken(ctx, id) if err != nil { return err } if token.Type != models.UserTokenTypeResetPassword { return ErrInvalidActivationKey } var data models.UserTokenData err = utils.FromJSON(token.Data, &data) if err != nil { return err } user, err := tx.FindUser(ctx, data.UserID) if err != nil { return err } err = validatePassword(user.Name, user.Email, newPassword) if err != nil { return err } hash, err := hashPassword(newPassword) if err != nil { return err } if err := tx.UpdateUserPassword(ctx, queries.UpdateUserPasswordParams{ ID: user.ID, PasswordHash: hash, }); err != nil { return err } return tx.DeleteUserToken(ctx, id) } ================================================ FILE: internal/service/user/apikey.go ================================================ package user import ( "errors" "time" "github.com/golang-jwt/jwt/v5" "github.com/stashapp/stash-box/internal/config" ) var ErrInvalidToken = errors.New("invalid apikey") const APIKeySubject = "APIKey" type APIKeyClaims struct { UserID string `json:"uid"` jwt.RegisteredClaims } func generateAPIKey(userID string) (string, error) { claims := &APIKeyClaims{ UserID: userID, RegisteredClaims: jwt.RegisteredClaims{ Subject: APIKeySubject, IssuedAt: jwt.NewNumericDate(time.Now()), }, } token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) ss, err := token.SignedString(config.GetJWTSignKey()) if err != nil { return "", err } return ss, nil } // GetUserIDFromAPIKey validates the provided api key and returns the user ID func GetUserIDFromAPIKey(apiKey string) (string, error) { claims := &APIKeyClaims{} token, err := jwt.ParseWithClaims(apiKey, claims, func(t *jwt.Token) (interface{}, error) { return config.GetJWTSignKey(), nil }) if err != nil { return "", err } if !token.Valid { return "", ErrInvalidToken } return claims.UserID, nil } ================================================ FILE: internal/service/user/invite.go ================================================ package user import ( "context" "errors" "fmt" "time" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/internal/queries" ) var ErrNoInviteTokens = errors.New("no invite tokens available") var ErrInvalidInviteKey = errors.New("invalid or expired invite key") type Finder interface { Find(id uuid.UUID) (*models.User, error) } type FinderUpdater interface { Finder UpdateFull(updatedUser models.User) (*models.User, error) } // GrantInviteTokens increments the invite token count for a user by up to 10. func grantInviteTokens(ctx context.Context, tx *queries.Queries, userID uuid.UUID, tokens int) (int, error) { u, err := tx.FindUser(ctx, userID) if err != nil { return 0, err } // don't accept negative numbers if tokens < 0 { return int(u.InviteTokens), nil } // put a sensible limit on the number of tokens that can be granted at a time const maxTokens = 10 if tokens > maxTokens { tokens = maxTokens } u.InviteTokens += tokens err = tx.UpdateUserInviteTokenCount(ctx, queries.UpdateUserInviteTokenCountParams{ ID: u.ID, InviteTokens: u.InviteTokens, }) return int(u.InviteTokens), err } // RepealInviteTokens decrements a user's invite token count by the provided // amount. Invite tokens are constrained to a minimum of 0. func repealInviteTokens(ctx context.Context, tx *queries.Queries, userID uuid.UUID, tokens int) (int, error) { u, err := tx.FindUser(ctx, userID) if err != nil { return 0, err } // don't accept negative numbers if tokens < 0 { return int(u.InviteTokens), nil } // no limit on the tokens to repeal u.InviteTokens -= tokens // don't allow to go negative if u.InviteTokens < 0 { u.InviteTokens = 0 } err = tx.UpdateUserInviteTokenCount(ctx, queries.UpdateUserInviteTokenCountParams{ ID: u.ID, InviteTokens: u.InviteTokens, }) return int(u.InviteTokens), err } // GenerateInviteKeys creates and returns an invite key, using a token if // required. If useToken is true and the user has no invite tokens, then // an error is returned. func generateInviteKeys(ctx context.Context, tx *queries.Queries, userID uuid.UUID, input *models.GenerateInviteCodeInput, useToken bool) ([]uuid.UUID, error) { keys := 1 if input.Keys != nil { keys = *input.Keys } // don't allow more than 50 keys to be generated at a time if keys > 50 { keys = 50 } var ret []uuid.UUID for i := 0; i < keys; i++ { if useToken { u, err := tx.FindUser(ctx, userID) if err != nil { return nil, err } if u.InviteTokens <= 0 { return nil, ErrNoInviteTokens } _, err = repealInviteTokens(ctx, tx, userID, 1) if err != nil { return nil, err } } // create the invite key UUID, err := uuid.NewV4() if err != nil { return nil, err } newKey := queries.CreateInviteKeyParams{ ID: UUID, GeneratedBy: userID, } if input != nil { if input.Uses != nil && *input.Uses > 0 { uses := *input.Uses newKey.Uses = &uses } if input.TTL != nil { expires := time.Now().Add(time.Duration(*input.TTL) * time.Second) newKey.ExpireTime = &expires } } key, err := tx.CreateInviteKey(ctx, newKey) if err != nil { return nil, err } ret = append(ret, key.ID) } return ret, nil } // RescindInviteKey makes an invite key invalid, refunding the invite token if // required. Returns an error if the invite key is already in use. func rescindInviteKey(ctx context.Context, tx *queries.Queries, key uuid.UUID, userID uuid.UUID, refundToken bool) error { // ensure userID matches that of the invite key k, err := tx.FindInviteKey(ctx, key) if err != nil { return err } if k.GeneratedBy != userID { return fmt.Errorf("invalid key") } // TODO - ensure key is not already activated // destroy the key err = tx.DeleteInviteKey(ctx, key) if err != nil { return err } // refund the invite token if required if refundToken { _, err := tx.FindUser(ctx, userID) if err != nil { return err } _, err = grantInviteTokens(ctx, tx, userID, 1) if err != nil { return err } } return nil } ================================================ FILE: internal/service/user/joins.go ================================================ package user import ( "context" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/internal/queries" ) func createRoles(ctx context.Context, tx *queries.Queries, userID uuid.UUID, roles []models.RoleEnum) error { var params []queries.CreateUserRolesParams for _, role := range roles { params = append(params, queries.CreateUserRolesParams{ UserID: userID, Role: role.String(), }) } _, err := tx.CreateUserRoles(ctx, params) return err } func updateRoles(ctx context.Context, tx *queries.Queries, userID uuid.UUID, roles []models.RoleEnum) error { if err := tx.DeleteUserRoles(ctx, userID); err != nil { return err } return createRoles(ctx, tx, userID, roles) } func createNotificationSubscriptions(ctx context.Context, tx *queries.Queries, userID uuid.UUID, subscriptions []models.NotificationEnum) error { var params []queries.CreateUserNotificationSubscriptionsParams for _, sub := range subscriptions { params = append(params, queries.CreateUserNotificationSubscriptionsParams{ UserID: userID, Type: queries.NotificationType(sub.String()), }) } _, err := tx.CreateUserNotificationSubscriptions(ctx, params) return err } ================================================ FILE: internal/service/user/password.go ================================================ package user import "golang.org/x/crypto/bcrypt" func hashPassword(password string) (string, error) { hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) if err != nil { return "", err } return string(hash), nil } func isPasswordCorrect(hash string, password string) bool { err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) return err == nil } ================================================ FILE: internal/service/user/query.go ================================================ package user import ( "context" sq "github.com/Masterminds/squirrel" "github.com/stashapp/stash-box/internal/converter" "github.com/stashapp/stash-box/internal/models" queryhelper "github.com/stashapp/stash-box/internal/service/query" ) func (s *User) Query(ctx context.Context, input models.UserQueryInput) (*models.QueryUsersResultType, error) { psql := sq.StatementBuilder.PlaceholderFormat(sq.Dollar) query := psql.Select("*").From("users") // Apply name filter - search across name and email columns if input.Name != nil && *input.Name != "" { searchTerm := "%" + *input.Name + "%" query = query.Where( sq.Or{ sq.ILike{"users.name": searchTerm}, sq.ILike{"users.email": searchTerm}, }, ) } // Get count countQuery := psql.Select("COUNT(*)").FromSelect(query, "subquery") count, err := queryhelper.ExecuteCount(ctx, countQuery, s.queries.DB(), "QueryUsersCount") if err != nil { return nil, err } // Apply sort query = query.OrderBy("name ASC") // Apply pagination query = queryhelper.ApplyPagination(query, input.Page, input.PerPage) // Execute query users, err := queryhelper.ExecuteQuery(ctx, query, s.queries.DB(), converter.UserToModel, "QueryUsers") if err != nil { return nil, err } return &models.QueryUsersResultType{ Count: count, Users: users, }, nil } ================================================ FILE: internal/service/user/service.go ================================================ package user import ( "context" "errors" "flag" "fmt" "math/rand" "strings" "time" "github.com/gofrs/uuid" "github.com/jackc/pgx/v5" "github.com/stashapp/stash-box/internal/auth" "github.com/stashapp/stash-box/internal/config" "github.com/stashapp/stash-box/internal/converter" "github.com/stashapp/stash-box/internal/email" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/internal/queries" "github.com/stashapp/stash-box/internal/service/errutil" "github.com/stashapp/stash-box/pkg/utils" ) // User handles user-related operations type User struct { queries *queries.Queries withTxn queries.WithTxnFunc emailMgr *email.Manager } // NewUser creates a new user service func NewUser(queries *queries.Queries, withTxn queries.WithTxnFunc, emailMgr *email.Manager) *User { return &User{ queries: queries, withTxn: withTxn, emailMgr: emailMgr, } } // WithTxn executes a function within a transaction func (s *User) WithTxn(fn func(*queries.Queries) error) error { return s.withTxn(fn) } // Queries func (s *User) FindByID(ctx context.Context, id uuid.UUID) (*models.User, error) { user, err := s.queries.FindUser(ctx, id) if err != nil { return nil, errutil.IgnoreNotFound(err) } return converter.UserToModelPtr(user), nil } func (s *User) FindByName(ctx context.Context, name string) (*models.User, error) { user, err := s.queries.FindUserByName(ctx, strings.ToUpper(name)) return converter.UserToModelPtr(user), err } func (s *User) Count(ctx context.Context) (int, error) { count, err := s.queries.CountUsers(ctx) return int(count), err } func (s *User) CountVotesByType(ctx context.Context, userID uuid.UUID) (*models.UserVoteCount, error) { rows, err := s.queries.CountVotesByType(ctx, userID) if err != nil { return nil, err } var result models.UserVoteCount for _, row := range rows { count := int(row.Count) switch row.Vote { case "ACCEPT": result.Accept = count case "REJECT": result.Reject = count case "ABSTAIN": result.Abstain = count case "IMMEDIATE_ACCEPT": result.ImmediateAccept = count case "IMMEDIATE_REJECT": result.ImmediateReject = count } } return &result, nil } func (s *User) CountEditsByStatus(ctx context.Context, userID uuid.UUID) (*models.UserEditCount, error) { rows, err := s.queries.CountUserEditsByStatus(ctx, uuid.NullUUID{UUID: userID, Valid: true}) if err != nil { return nil, err } var result models.UserEditCount for _, row := range rows { count := int(row.Count) switch row.Status { case "ACCEPTED": result.Accepted = count case "REJECTED": result.Rejected = count case "PENDING": result.Pending = count case "IMMEDIATE_ACCEPTED": result.ImmediateAccepted = count case "IMMEDIATE_REJECTED": result.ImmediateRejected = count case "FAILED": result.Failed = count case "CANCELED": result.Canceled = count } } return &result, nil } func (s *User) GetNotificationSubscriptions(ctx context.Context, userID uuid.UUID) ([]models.NotificationEnum, error) { rows, err := s.queries.GetUserNotificationSubscriptions(ctx, userID) if err != nil { return nil, err } var notifications []models.NotificationEnum for _, row := range rows { notifications = append(notifications, models.NotificationEnum(row)) } return notifications, nil } func (s *User) GetRoles(ctx context.Context, userID uuid.UUID) ([]models.RoleEnum, error) { roleStrings, err := s.queries.GetUserRoles(ctx, userID) if err != nil { return nil, err } return converter.StringsToRoleEnums(roleStrings), nil } // NewUser registers a new user. It returns the activation key only if // email verification is not required, otherwise it returns nil. func (s *User) NewUser(ctx context.Context, emailAddr string, inviteKey *uuid.UUID) (*uuid.UUID, error) { // ensure user or pending activation with email does not already exist if err := validateUserEmail(emailAddr); err != nil { return nil, err } var err error var activationKey *uuid.UUID err = s.withTxn(func(tx *queries.Queries) error { if err := validateExistingEmail(ctx, tx, emailAddr); err != nil { return err } if err := validateInviteKey(ctx, tx, inviteKey); err != nil { return err } // generate an activation key and email activationToken, err := generateActivationKey(ctx, tx, emailAddr, inviteKey) if err != nil { return err } // if activation is not required, return the activation key to the frontend // so it can auto-navigate to the activation page if !config.GetRequireActivation() { activationKey = &activationToken.ID return nil } // if activation is required, send the email and return nil return email.SendNewUserEmail(emailAddr, activationToken.ID, s.emailMgr) }) return activationKey, err } func (s *User) Create(ctx context.Context, input models.UserCreateInput) (*models.User, error) { var user *models.User err := s.withTxn(func(tx *queries.Queries) error { createdUser, err := createUser(ctx, tx, input, true) if createdUser != nil { user = converter.UserToModelPtr(*createdUser) } return err }) return user, err } func (s *User) Update(ctx context.Context, input models.UserUpdateInput) (*models.User, error) { var user queries.User err := s.withTxn(func(tx *queries.Queries) error { existingUser, err := tx.FindUser(ctx, input.ID) if err != nil { return err } // Validate changes and permissions if err := validateUpdate(ctx, input, existingUser); err != nil { return err } hash := existingUser.PasswordHash if input.Password != nil { hash, err = hashPassword(*input.Password) if err != nil { return fmt.Errorf("error updating user") } } params := converter.UpdateUserFromUpdateInput(existingUser, input, hash) user, err = tx.UpdateUser(ctx, params) if err != nil { return err } // Update roles // TODO - only do this if provided return updateRoles(ctx, tx, user.ID, input.Roles) }) return converter.UserToModelPtr(user), err } func (s *User) Delete(ctx context.Context, input models.UserDestroyInput) error { return s.withTxn(func(tx *queries.Queries) error { existingUser, err := tx.FindUser(ctx, input.ID) if err != nil { return err } if err := validateDelete(existingUser); err != nil { return err } if err := tx.DeleteUser(ctx, input.ID); err != nil { return err } return tx.CancelUserEdits(ctx, uuid.NullUUID{UUID: input.ID, Valid: true}) }) } func (s *User) RegenerateAPIKey(ctx context.Context, userID *uuid.UUID) (string, error) { currentUser := auth.GetCurrentUser(ctx) if userID != nil { if currentUser.ID != *userID { // changing another user api key // must be admin if err := auth.ValidateAdmin(ctx); err != nil { return "", err } } } else { // changing current user api key userID = ¤tUser.ID } key := "" err := s.withTxn(func(tx *queries.Queries) error { user, err := tx.FindUser(ctx, *userID) if err != nil { return fmt.Errorf("error finding user: %w", err) } key, err = generateAPIKey(user.ID.String()) if err != nil { return fmt.Errorf("error generating APIKey: %w", err) } return tx.UpdateUserAPIKey(ctx, queries.UpdateUserAPIKeyParams{ ID: *userID, ApiKey: key, }) }) return key, err } func (s *User) ResetPassword(ctx context.Context, input models.ResetPasswordInput) error { return s.withTxn(func(tx *queries.Queries) error { u, err := tx.FindUserByEmail(ctx, input.Email) if err != nil { return err } // Sleep between 500-1500ms to avoid leaking email presence n := rand.Intn(1000) time.Sleep(time.Duration(500+n) * time.Millisecond) // generate an activation key and email key, err := generateResetPasswordActivationKey(ctx, tx, u.ID) if err != nil { return err } return email.SendResetPasswordEmail(u, *key, s.emailMgr) }) } func (s *User) ChangePassword(ctx context.Context, input models.UserChangePasswordInput) error { currentUser := auth.GetCurrentUser(ctx) if input.ResetKey != nil { return s.withTxn(func(tx *queries.Queries) error { return activateResetPassword(ctx, tx, *input.ResetKey, input.NewPassword) }) } // just setting password if currentUser == nil { return auth.ErrUnauthorized } if input.ExistingPassword == nil { return ErrCurrentPasswordIncorrect } return s.withTxn(func(tx *queries.Queries) error { return changePassword(ctx, tx, currentUser.ID, *input.ExistingPassword, input.NewPassword) }) } func (s *User) ActivateNewUser(ctx context.Context, input models.ActivateNewUserInput) (*models.User, error) { var user queries.User err := s.withTxn(func(tx *queries.Queries) error { token, err := tx.FindUserToken(ctx, input.ActivationKey) if err != nil { if errors.Is(err, pgx.ErrNoRows) { return ErrInvalidActivationKey } return err } if token.Type != models.UserTokenTypeNewUser { return ErrInvalidActivationKey } data, err := getNewUserTokenData(token) if err != nil { return err } var invitedBy *uuid.UUID if config.GetRequireInvite() { if data.InviteKey == nil { return errors.New("cannot find invite key") } invite, err := tx.FindInviteKey(ctx, *data.InviteKey) if err != nil { if errors.Is(err, pgx.ErrNoRows) { return ErrInvalidInviteKey } return err } invitedBy = &invite.GeneratedBy } createInput := models.UserCreateInput{ Name: input.Name, Email: data.Email, Password: input.Password, InvitedByID: invitedBy, Roles: getDefaultUserRoles(), } if _, err := tx.FindUserByName(ctx, createInput.Name); !errors.Is(err, pgx.ErrNoRows) { if err != nil { return err } return errors.New("username already used") } createdUser, err := createUser(ctx, tx, createInput, true) if err != nil { return err } user = *createdUser // delete the activation if err := tx.DeleteUserToken(ctx, token.ID); err != nil { return err } if config.GetRequireInvite() { // decrement the invite key uses usesLeft, err := tx.InviteKeyUsed(ctx, *data.InviteKey) // Ignore "no rows" error - this happens when the invite key has unlimited uses (NULL) if err != nil && !errors.Is(err, pgx.ErrNoRows) { return err } // if all used up, then delete the invite key if usesLeft != nil && *usesLeft <= 0 { // delete the invite key if err := tx.DeleteInviteKey(ctx, *data.InviteKey); err != nil { return err } } } return nil }) return converter.UserToModelPtr(user), err } func (s *User) GenerateInviteCodes(ctx context.Context, input *models.GenerateInviteCodeInput) ([]uuid.UUID, error) { // INVITE role allows generating invite keys without tokens requireToken := true if err := auth.ValidateInvite(ctx); err == nil { requireToken = false } currentUser := auth.GetCurrentUser(ctx) var ret []uuid.UUID err := s.withTxn(func(tx *queries.Queries) error { keys, err := generateInviteKeys(ctx, tx, currentUser.ID, input, requireToken) if err != nil { return err } ret = append(ret, keys...) return nil }) return ret, err } func (s *User) GenerateInviteCode(ctx context.Context) (*uuid.UUID, error) { // INVITE role allows generating invite keys without tokens requireToken := true if err := auth.ValidateInvite(ctx); err == nil { requireToken = false } currentUser := auth.GetCurrentUser(ctx) var ret *uuid.UUID err := s.withTxn(func(tx *queries.Queries) error { keys := 1 uses := 1 input := &models.GenerateInviteCodeInput{ Keys: &keys, Uses: &uses, } inviteKeys, txnErr := generateInviteKeys(ctx, tx, currentUser.ID, input, requireToken) if txnErr != nil { return txnErr } if len(inviteKeys) == 0 { return errors.New("no invite code generated") } ret = &inviteKeys[0] return nil }) return ret, err } func (s *User) RescindInviteCode(ctx context.Context, inviteKeyID uuid.UUID) error { // INVITE role allows generating invite keys without tokens requireToken := true if err := auth.ValidateInvite(ctx); err == nil { requireToken = false } tokenManagerErr := auth.ValidateManageInvites(ctx) currentUser := auth.GetCurrentUser(ctx) return s.withTxn(func(tx *queries.Queries) error { userID := currentUser.ID // Non-token managers may only rescind their own invite code if tokenManagerErr == nil { inviteKey, err := tx.FindInviteKey(ctx, inviteKeyID) if err != nil { return err } userID = inviteKey.GeneratedBy } err := rescindInviteKey(ctx, tx, inviteKeyID, userID, requireToken) if err != nil { return err } return nil }) } func (s *User) GrantInvite(ctx context.Context, input models.GrantInviteInput) (int, error) { if err := auth.ValidateManageInvites(ctx); err != nil { return 0, err } var ret int err := s.withTxn(func(tx *queries.Queries) error { count, err := grantInviteTokens(ctx, tx, input.UserID, input.Amount) ret = count return err }) return ret, err } func (s *User) RevokeInvite(ctx context.Context, input models.RevokeInviteInput) (int, error) { if err := auth.ValidateManageInvites(ctx); err != nil { return 0, err } var ret int err := s.withTxn(func(tx *queries.Queries) error { count, err := repealInviteTokens(ctx, tx, input.UserID, input.Amount) ret = count return err }) return ret, err } func (s *User) RequestChangeEmail(ctx context.Context) (models.UserChangeEmailStatus, error) { currentUser := auth.GetCurrentUser(ctx) err := s.withTxn(func(tx *queries.Queries) error { return email.ConfirmOldEmail(ctx, tx, *currentUser, s.emailMgr) }) if err != nil { return models.UserChangeEmailStatusError, err } return models.UserChangeEmailStatusConfirmOld, nil } func (s *User) ValidateChangeEmail(ctx context.Context, tokenID uuid.UUID, emailAddr string) (models.UserChangeEmailStatus, error) { err := s.withTxn(func(tx *queries.Queries) error { token, err := tx.FindUserToken(ctx, tokenID) if err != nil { return err } data, err := getUserTokenData(token) if err != nil { return err } currentUser := auth.GetCurrentUser(ctx) if data.UserID != currentUser.ID { return fmt.Errorf("invalid token") } return email.ConfirmNewEmail(ctx, tx, *currentUser, emailAddr, s.emailMgr) }) if err != nil { return models.UserChangeEmailStatusError, err } return models.UserChangeEmailStatusConfirmNew, nil } func (s *User) ConfirmChangeEmail(ctx context.Context, tokenID uuid.UUID) (models.UserChangeEmailStatus, error) { err := s.withTxn(func(tx *queries.Queries) error { token, err := tx.FindUserToken(ctx, tokenID) if err != nil { return err } data, err := getChangeEmailTokenData(token) if err != nil { return err } currentUser := auth.GetCurrentUser(ctx) if data.UserID != currentUser.ID { return fmt.Errorf("invalid token") } return email.ChangeEmail(ctx, tx, data) }) if err != nil { return models.UserChangeEmailStatusError, err } return models.UserChangeEmailStatusSuccess, nil } func (s *User) CreateSystemUsers(ctx context.Context) { // if there are no users present, then create a root user with a // generated password and api key, outputting them var rootPassword string var createdUser *models.User err := s.withTxn(func(tx *queries.Queries) error { _, err := tx.FindUserByName(ctx, rootUserName) if err != nil && !errors.Is(err, pgx.ErrNoRows) { panic(fmt.Errorf("error getting root user: %w", err)) } if errors.Is(err, pgx.ErrNoRows) { rootPassword, err = utils.GenerateRandomPassword(16) if err != nil { panic(fmt.Errorf("error creating root user: %w", err)) } newUser := models.UserCreateInput{ Name: rootUserName, Password: rootPassword, Email: unsetEmail, Roles: rootUserRoles, } dbUser, err := createUser(ctx, tx, newUser, false) if err != nil { return err } createdUser = converter.UserToModelPtr(*dbUser) } _, err = tx.FindUserByName(ctx, modUserName) if err != nil && !errors.Is(err, pgx.ErrNoRows) { panic(fmt.Errorf("error getting mod user: %w", err)) } if errors.Is(err, pgx.ErrNoRows) { password, err := utils.GenerateRandomPassword(32) if err != nil { panic(fmt.Errorf("error creating root user: %w", err)) } newUser := models.UserCreateInput{ Name: modUserName, Password: password, Email: "stashbot@example.com", Roles: modUserRoles, } if _, err = createUser(ctx, tx, newUser, false); err != nil { return err } } return nil }) if err != nil { panic(fmt.Errorf("error creating system users: %w", err)) } if createdUser != nil { // print (not log) the details of the created user // Skip output during tests if flag.Lookup("test.v") == nil { fmt.Printf("root user has been created.\nUser: %s\nPassword: %s\nAPI Key: %s\n", rootUserName, rootPassword, createdUser.APIKey) fmt.Print("These credentials have not been logged. The email should be set and the password should be changed after logging in.\n") } } } // Authenticate validates the provided username and password. If correct, it // returns the id of the user. func (s *User) Authenticate(ctx context.Context, username string, password string) (string, error) { user, err := s.queries.FindUserByName(ctx, username) if err != nil { return "", err } if !isPasswordCorrect(user.PasswordHash, password) { return "", ErrAccessDenied } return user.ID.String(), nil } ================================================ FILE: internal/service/user/token.go ================================================ package user import ( "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/internal/queries" "github.com/stashapp/stash-box/pkg/utils" ) func getNewUserTokenData(token queries.UserToken) (models.NewUserTokenData, error) { var obj models.NewUserTokenData err := utils.FromJSON(token.Data, &obj) return obj, err } func getUserTokenData(token queries.UserToken) (models.UserTokenData, error) { var obj models.UserTokenData err := utils.FromJSON(token.Data, &obj) return obj, err } func getChangeEmailTokenData(token queries.UserToken) (models.ChangeEmailTokenData, error) { var obj models.ChangeEmailTokenData err := utils.FromJSON(token.Data, &obj) return obj, err } ================================================ FILE: internal/service/user/user.go ================================================ package user import ( "context" "errors" "fmt" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/config" "github.com/stashapp/stash-box/internal/converter" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/internal/queries" ) const ( minPasswordLength = 8 maxPasswordLength = 64 minUniqueChars = 5 rootUserName = "root" modUserName = "StashBot" unsetEmail = "root@example.com" ) var ( ErrUserNotExist = errors.New("user not found") ErrEmptyUsername = errors.New("empty username") ErrUsernameHasWhitespace = errors.New("username has leading or trailing whitespace") ErrUsernameMatchesEmail = errors.New("username is the same as email") ErrEmptyEmail = errors.New("empty email") ErrEmailHasWhitespace = errors.New("email has leading or trailing whitespace") ErrInvalidEmail = errors.New("not a valid email address") ErrPasswordTooShort = fmt.Errorf("password length < %d", minPasswordLength) ErrPasswordTooLong = fmt.Errorf("password > %d", maxPasswordLength) ErrPasswordInsufficientUniqueChars = fmt.Errorf("password has < %d unique characters", minUniqueChars) ErrBannedPassword = errors.New("password matches a common password") ErrPasswordUsername = errors.New("password matches username") ErrPasswordEmail = errors.New("password matches email") ErrDeleteSystemUser = errors.New("system users cannot be deleted") ErrChangeModUser = errors.New("mod user cannot be modified") ErrChangeRootName = errors.New("cannot change root username") ErrChangeRootRoles = errors.New("cannot change root roles") ErrAccessDenied = errors.New("access denied") ErrCurrentPasswordIncorrect = errors.New("current password incorrect") ) var rootUserRoles []models.RoleEnum = []models.RoleEnum{ models.RoleEnumAdmin, } var modUserRoles []models.RoleEnum = []models.RoleEnum{ models.RoleEnumBot, } func createUser(ctx context.Context, tx *queries.Queries, input models.UserCreateInput, defaultNotifications bool) (*queries.User, error) { if err := validateCreate(input); err != nil { return nil, err } id, err := uuid.NewV7() if err != nil { return nil, err } hash, err := hashPassword(input.Password) if err != nil { return nil, err } key, err := generateAPIKey(id.String()) if err != nil { return nil, err } params := converter.UserCreateInputToCreateParams(input, id, hash, key) user, err := tx.CreateUser(ctx, params) if err != nil { return nil, err } if err := createRoles(ctx, tx, id, input.Roles); err != nil { return nil, err } if defaultNotifications { err = createNotificationSubscriptions(ctx, tx, id, models.GetDefaultNotificationSubscriptions()) } return &user, err } func changePassword(ctx context.Context, tx *queries.Queries, userID uuid.UUID, currentPassword string, newPassword string) error { user, err := tx.FindUser(ctx, userID) if err != nil { return fmt.Errorf("error finding user: %w", err) } if !isPasswordCorrect(user.PasswordHash, currentPassword) { return ErrCurrentPasswordIncorrect } err = validatePassword(user.Name, user.Email, newPassword) if err != nil { return err } hash, err := hashPassword(newPassword) if err != nil { return err } return tx.UpdateUserPassword(ctx, queries.UpdateUserPasswordParams{ ID: user.ID, PasswordHash: hash, }) } func getDefaultUserRoles() []models.RoleEnum { roleStr := config.GetDefaultUserRoles() ret := []models.RoleEnum{} for _, v := range roleStr { e := models.RoleEnum(v) if e.IsValid() { ret = append(ret, e) } } return ret } ================================================ FILE: internal/service/user/validate.go ================================================ package user import ( "context" "errors" "regexp" "strings" "time" "github.com/gofrs/uuid" "github.com/jackc/pgx/v5" "github.com/stashapp/stash-box/internal/auth" "github.com/stashapp/stash-box/internal/config" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/internal/queries" "github.com/stashapp/stash-box/pkg/utils" ) func validateCreate(input models.UserCreateInput) error { // username must be set err := validateUserName(input.Name, &input.Email) if err != nil { return err } // email must be valid err = validateUserEmail(input.Email) if err != nil { return err } // password must be valid according to policy err = validatePassword(input.Name, input.Email, input.Password) if err != nil { return err } return nil } func validateUpdate(ctx context.Context, input models.UserUpdateInput, current queries.User) error { currentName := current.Name currentEmail := current.Email if currentName == modUserName { return ErrChangeModUser } if currentName == rootUserName { if input.Name != nil && *input.Name != rootUserName { return ErrChangeRootName } // TODO - this means that we must include roles in the input if len(input.Roles) != len(rootUserRoles) || input.Roles[0] != rootUserRoles[0] { return ErrChangeRootRoles } } if input.Name != nil { currentName = *input.Name err := validateUserName(*input.Name, input.Email) if err != nil { return err } } // email must be valid if input.Email != nil { currentEmail = *input.Email err := validateUserEmail(*input.Email) if err != nil { return err } } else if current.Email == unsetEmail { return ErrEmptyEmail } // password must be valid according to policy if input.Password != nil { err := validatePassword(currentName, currentEmail, *input.Password) if err != nil { return err } } if input.Name != nil && *input.Name != current.Name { if err := auth.ValidateAdmin(ctx); err != nil { return err } } return nil } func validateDelete(user queries.User) error { if user.Name == rootUserName || user.Name == modUserName { return ErrDeleteSystemUser } return nil } func validateUserName(username string, email *string) error { if username == "" { return ErrEmptyUsername } // username must not have leading or trailing whitespace trimmed := strings.TrimSpace(username) if trimmed != username { return ErrUsernameHasWhitespace } if email != nil && *email == trimmed { return ErrUsernameMatchesEmail } return nil } func validateUserEmail(emailAddr string) error { if emailAddr == "" { return ErrEmptyEmail } // email must not have leading or trailing whitespace trimmed := strings.TrimSpace(emailAddr) if trimmed != emailAddr { return ErrEmailHasWhitespace } // from https://stackoverflow.com/a/201378 const emailRegex = "(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*\")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\\])" re := regexp.MustCompile(emailRegex) if !re.MatchString(emailAddr) { return ErrInvalidEmail } return nil } func countUniqueCharacters(str string) int { chars := make(map[rune]bool) for _, r := range str { chars[r] = true } return len(chars) } func validatePassword(username string, emailAddr string, password string) error { // TODO - hardcode these policies for now. We may want to make these // configurable in future if len(password) < minPasswordLength { return ErrPasswordTooShort } if len(password) > maxPasswordLength { return ErrPasswordTooLong } if countUniqueCharacters(password) < minUniqueChars { return ErrPasswordInsufficientUniqueChars } // ensure password doesn't match the top 10,000 passwords over the minimum length if utils.IsBannedPassword(password) { return ErrBannedPassword } // ensure password doesn't match the username or email if password == username { return ErrPasswordUsername } if password == emailAddr { return ErrPasswordEmail } return nil } func validateExistingEmail(ctx context.Context, tx *queries.Queries, emailAddr string) error { // Check if a user with this email already exists _, err := tx.FindUserByEmail(ctx, emailAddr) if errors.Is(err, pgx.ErrNoRows) { // No existing user, now check for pending activations tokens, err := tx.FindUserTokensByEmail(ctx, emailAddr) if err != nil { return err } // Filter to only new user tokens (pending activations) for _, token := range tokens { if token.Type == models.UserTokenTypeNewUser { return errors.New("email already has a pending activation") } } return nil } if err != nil { return err } return errors.New("email already in use") } func validateInviteKey(ctx context.Context, tx *queries.Queries, inviteKey *uuid.UUID) error { if config.GetRequireInvite() { if inviteKey == nil { return errors.New("invite key required") } key, err := tx.FindInviteKey(ctx, *inviteKey) if err != nil { return err } // ensure invite key is not expired if key.ExpireTime != nil && key.ExpireTime.Before(time.Now()) { return errors.New("invite key expired") } // ensure key isn't already used t, _ := tx.FindUserTokensByInviteKey(ctx, *inviteKey) if key.Uses != nil && len(t) >= int(*key.Uses) { return errors.New("key already used") } } return nil } ================================================ FILE: internal/service/usertoken/service.go ================================================ package usertoken import ( "context" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/converter" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/internal/queries" ) // UserToken handles user token related operations type UserToken struct { queries *queries.Queries withTxn queries.WithTxnFunc } // NewUserToken creates a new user token service func NewUserToken(queries *queries.Queries, withTxn queries.WithTxnFunc) *UserToken { return &UserToken{ queries: queries, withTxn: withTxn, } } // WithTxn executes a function within a transaction func (s *UserToken) WithTxn(fn func(*queries.Queries) error) error { return s.withTxn(fn) } // Create creates a new user token func (s *UserToken) Create(ctx context.Context, newToken models.UserToken) (*models.UserToken, error) { // Convert GraphQL model to sqlc parameters params := queries.CreateUserTokenParams{ ID: newToken.ID, Type: newToken.Type, CreatedAt: newToken.CreatedAt, ExpiresAt: newToken.ExpiresAt, } // Convert the JSON data if len(newToken.Data) > 0 { params.Data = []byte(newToken.Data) } createdToken, err := s.queries.CreateUserToken(ctx, params) if err != nil { return nil, err } return converter.UserTokenToModelPtr(createdToken), nil } // Destroy deletes a user token by ID func (s *UserToken) Destroy(ctx context.Context, id uuid.UUID) error { return s.queries.DeleteUserToken(ctx, id) } // DestroyExpired deletes all expired user tokens func (s *UserToken) DestroyExpired(ctx context.Context) error { return s.queries.DeleteExpiredUserTokens(ctx) } // Find finds a user token by ID func (s *UserToken) Find(ctx context.Context, id uuid.UUID) (*models.UserToken, error) { token, err := s.queries.FindUserToken(ctx, id) if err != nil { return nil, err } return converter.UserTokenToModelPtr(token), nil } // FindByInviteKey finds user tokens by invite key in JSON data func (s *UserToken) FindByInviteKey(ctx context.Context, key uuid.UUID) ([]*models.UserToken, error) { tokens, err := s.queries.FindUserTokensByInviteKey(ctx, key) if err != nil { return nil, err } var result []*models.UserToken for _, token := range tokens { result = append(result, converter.UserTokenToModelPtr(token)) } return result, nil } // FindActiveInviteKeysForUser returns active invite keys for a specific user func (s *UserToken) FindActiveInviteKeysForUser(ctx context.Context, userID uuid.UUID) ([]models.InviteKey, error) { keys, err := s.queries.FindActiveInviteKeysForUser(ctx, userID) if err != nil { return nil, err } return converter.InviteKeysToModels(keys), nil } ================================================ FILE: internal/storage/favicon.go ================================================ package storage import ( "context" "errors" "io" "net/http" "net/http/cookiejar" "net/url" "os" "path" "sync" "github.com/gofrs/uuid" "github.com/stashapp/stash-box/internal/config" "github.com/stashapp/stash-box/internal/models" "go.deanishe.net/favicon" "golang.org/x/net/publicsuffix" ) var iconCache = map[uuid.UUID][]byte{} var iconCacheMutex = &sync.RWMutex{} func getCachedSiteIcon(site *models.Site) ([]byte, bool) { iconCacheMutex.RLock() defer iconCacheMutex.RUnlock() if cachedIcon, hasIcon := iconCache[site.ID]; hasIcon { return cachedIcon, true } return nil, false } func GetSiteIcon(ctx context.Context, site models.Site) ([]byte, error) { if cachedIcon, hasIcon := getCachedSiteIcon(&site); hasIcon { return cachedIcon, nil } if site.URL == nil { return nil, nil } faviconPath, err := config.GetFaviconPath() if faviconPath == nil { return nil, err } iconPath := path.Join(*faviconPath, site.ID.String()) if _, err := os.Stat(iconPath); os.IsNotExist(err) { if err := downloadIcon(ctx, iconPath, *site.URL); err != nil { return nil, err } } else if err != nil { return nil, err } data, err := os.ReadFile(iconPath) if err != nil || len(data) == 0 { return nil, err } iconCacheMutex.Lock() defer iconCacheMutex.Unlock() iconCache[site.ID] = data return iconCache[site.ID], nil } func downloadIcon(ctx context.Context, iconPath string, siteURL string) error { err := errors.New("no site url given") if siteURL == "" { return err } u, err := url.Parse(siteURL) if err != nil { return err } // We need a client with a cookiejar for the favicon finder because some websites // simply don't work without cookies. // For instance, at the time of writing, twitter.com returns an http 302 redirect // with location `/` and a `guest_id` cookie. We must include this cookie // in the subsequent request otherwise we are stuck in a redirect loop. jar, err := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List}) if err != nil { return err } c := &http.Client{Jar: jar} finder := favicon.New(favicon.WithClient(c)) icons, err := finder.Find(u.Scheme + "://" + u.Host) if err != nil || len(icons) < 1 { return err } // Icons are sorted widest first. Based on the design of the stash-box UI, // it makes sense to grab the _smallest_ icon, i.e. the last one. // TODO: Find the ideal size favicon for the stash-box UI and try to get the same here. req, err := http.NewRequestWithContext(ctx, http.MethodGet, icons[len(icons)-1].URL, nil) if err != nil { return err } resp, err := http.DefaultClient.Do(req) if err != nil { return err } defer resp.Body.Close() out, err := os.Create(iconPath) if err != nil { return err } defer out.Close() if _, err := io.Copy(out, resp.Body); err != nil { return err } return nil } ================================================ FILE: internal/storage/file.go ================================================ package storage import ( "io" "os" "path/filepath" "github.com/stashapp/stash-box/internal/config" "github.com/stashapp/stash-box/internal/models" "github.com/stashapp/stash-box/pkg/utils" ) type FileBackend struct{} func (s *FileBackend) WriteFile(file []byte, image *models.Image) error { if err := config.ValidateImageLocation(); err != nil { return err } fileDir := config.GetImageLocation() // check fileDir for the identical file fn := GetImagePath(fileDir, image.Checksum) if exists, _ := utils.FileExists(fn); exists { // file already exists return nil } // write the file path := GetImagePath(fileDir, image.Checksum) if err := os.WriteFile(path, file, os.FileMode(0644)); err != nil { _ = os.Remove(path) return err } return nil } func (s *FileBackend) DestroyFile(image *models.Image) error { return os.Remove(GetImagePath(config.GetImageLocation(), image.Checksum)) } func (s *FileBackend) ReadFile(image models.Image) (io.ReadCloser, int64, error) { fileDir := config.GetImageLocation() path := GetImagePath(fileDir, image.Checksum) stat, err := os.Stat(path) if err != nil { return nil, 0, err } file, err := os.Open(path) return file, stat.Size(), err } func GetImagePath(imageDir string, checksum string) string { return filepath.Join(imageDir, checksum) } ================================================ FILE: internal/storage/image_backend.go ================================================ package storage import ( "io" "github.com/stashapp/stash-box/internal/config" "github.com/stashapp/stash-box/internal/models" ) type Backend interface { WriteFile(file []byte, image *models.Image) error DestroyFile(image *models.Image) error ReadFile(image models.Image) (io.ReadCloser, int64, error) } func Image() Backend { imageBackend := config.GetImageBackend() var backend Backend switch imageBackend { case config.FileBackend: backend = &FileBackend{} case config.S3Backend: backend = &S3Backend{} } return backend } ================================================ FILE: internal/storage/s3.go ================================================ package storage import ( "bytes" "context" "fmt" "io" "net/http" "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" "github.com/stashapp/stash-box/internal/config" "github.com/stashapp/stash-box/internal/models" ) type S3Backend struct{} func (s *S3Backend) WriteFile(file []byte, image *models.Image) error { s3config := config.GetS3Config() headers := s3config.UploadHeaders minioClient, err := minio.New(s3config.Endpoint, &minio.Options{ Creds: credentials.NewStaticV4(s3config.AccessKey, s3config.Secret, ""), Secure: true, }) if err != nil { return fmt.Errorf("creating minio client: %w", err) } if err := uploadS3File(minioClient, file, s3config.Bucket, image.ID.String(), headers); err != nil { return fmt.Errorf("uploading to s3: %w", err) } return nil } func (s *S3Backend) DestroyFile(image *models.Image) error { s3config := config.GetS3Config() minioClient, err := minio.New(s3config.Endpoint, &minio.Options{ Creds: credentials.NewStaticV4(s3config.AccessKey, s3config.Secret, ""), Secure: true, }) if err != nil { return err } id := image.ID.String() path := id[0:2] + "/" + id[2:4] + "/" + id err = minioClient.RemoveObject(context.TODO(), s3config.Bucket, path, minio.RemoveObjectOptions{}) if err != nil { return err } return nil } func uploadS3File(client *minio.Client, file []byte, bucket string, id string, headers map[string]string) error { ctx := context.TODO() // SVG is not correctly detected so we set it manually if the file is xml contentType := http.DetectContentType(file) if contentType == "text/xml; charset=utf-8" || contentType == "text/plain; charset=utf-8" { contentType = "image/svg+xml" } path := id[0:2] + "/" + id[2:4] + "/" + id _, err := client.PutObject( ctx, bucket, path, bytes.NewReader(file), int64(len(file)), minio.PutObjectOptions{ ContentType: contentType, UserMetadata: headers, }, ) return err } func (s *S3Backend) ReadFile(image models.Image) (io.ReadCloser, int64, error) { ctx := context.TODO() s3config := config.GetS3Config() minioClient, err := minio.New(s3config.Endpoint, &minio.Options{ Creds: credentials.NewStaticV4(s3config.AccessKey, s3config.Secret, ""), Secure: true, }) if err != nil { return nil, 0, err } id := image.ID.String() path := id[0:2] + "/" + id[2:4] + "/" + id object, err := minioClient.GetObject( ctx, s3config.Bucket, path, minio.GetObjectOptions{}, ) if err != nil { return nil, 0, err } stat, err := object.Stat() if err != nil { return nil, 0, err } return object, stat.Size, err } ================================================ FILE: pkg/logger/logger.go ================================================ package logger import ( "fmt" "io" "os" "sync" "time" "github.com/sirupsen/logrus" ) type LogItem struct { Time time.Time `json:"time"` Type string `json:"type"` Message string `json:"message"` } var logger = logrus.New() var progressLogger = logrus.New() // separate log for user management var userLogger = logrus.New() var LogCache []LogItem var mutex = &sync.Mutex{} var logSubs []chan []LogItem var waiting = false var lastBroadcast = time.Now() var logBuffer []LogItem // Init initialises the logger based on a logging configuration func Init(logFile string, userLogFile string, logOut bool, logLevel string) { file := openLogFile(logFile) if file != nil && logOut { mw := io.MultiWriter(os.Stderr, file) logger.Out = mw } else if file != nil { logger.Out = file } // otherwise, output to StdErr SetLogLevel(logLevel) // initialise user log userFile := openLogFile(userLogFile) if userFile != nil { userLogger.Out = userFile } } func openLogFile(logFile string) *os.File { var file *os.File if logFile != "" { var err error file, err = os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) if err != nil { fmt.Printf("Could not open '%s' for log output due to error: %s\n", logFile, err.Error()) } } return file } func SetLogLevel(level string) { logger.Level = logLevelFromString(level) } func logLevelFromString(level string) logrus.Level { ret := logrus.InfoLevel switch level { case "Debug": ret = logrus.DebugLevel case "Warning": ret = logrus.WarnLevel case "Error": ret = logrus.ErrorLevel } return ret } func addLogItem(l *LogItem) { mutex.Lock() l.Time = time.Now() LogCache = append([]LogItem{*l}, LogCache...) if len(LogCache) > 30 { LogCache = LogCache[:len(LogCache)-1] } mutex.Unlock() go broadcastLogItem(l) } func GetLogCache() []LogItem { mutex.Lock() ret := make([]LogItem, len(LogCache)) copy(ret, LogCache) mutex.Unlock() return ret } func SubscribeToLog(stop chan int) <-chan []LogItem { ret := make(chan []LogItem, 100) go func() { <-stop unsubscribeFromLog(ret) }() mutex.Lock() logSubs = append(logSubs, ret) mutex.Unlock() return ret } func unsubscribeFromLog(toRemove chan []LogItem) { mutex.Lock() for i, c := range logSubs { if c == toRemove { logSubs = append(logSubs[:i], logSubs[i+1:]...) } } close(toRemove) mutex.Unlock() } func doBroadcastLogItems() { // assumes mutex held for _, c := range logSubs { // don't block waiting to broadcast select { case c <- logBuffer: default: } } logBuffer = nil waiting = false lastBroadcast = time.Now() } func broadcastLogItem(l *LogItem) { mutex.Lock() logBuffer = append(logBuffer, *l) // don't send more than once per second if !waiting { // if last broadcast was under a second ago, wait until a second has // passed timeSinceBroadcast := time.Since(lastBroadcast) if timeSinceBroadcast.Seconds() < 1 { waiting = true time.AfterFunc(time.Second-timeSinceBroadcast, func() { mutex.Lock() doBroadcastLogItems() mutex.Unlock() }) } else { doBroadcastLogItems() } } // if waiting then adding it to the buffer is sufficient mutex.Unlock() } func init() { progressLogger.SetFormatter(new(ProgressFormatter)) } func Progressf(format string, args ...interface{}) { progressLogger.Infof(format, args...) l := &LogItem{ Type: "progress", Message: fmt.Sprintf(format, args...), } addLogItem(l) } func Trace(args ...interface{}) { logger.Trace(args...) } func Debug(args ...interface{}) { logger.Debug(args...) l := &LogItem{ Type: "debug", Message: fmt.Sprint(args...), } addLogItem(l) } func Debugf(format string, args ...interface{}) { logger.Debugf(format, args...) l := &LogItem{ Type: "debug", Message: fmt.Sprintf(format, args...), } addLogItem(l) } func Info(args ...interface{}) { logger.Info(args...) l := &LogItem{ Type: "info", Message: fmt.Sprint(args...), } addLogItem(l) } func Infof(format string, args ...interface{}) { logger.Infof(format, args...) l := &LogItem{ Type: "info", Message: fmt.Sprintf(format, args...), } addLogItem(l) } func Warn(args ...interface{}) { logger.Warn(args...) l := &LogItem{ Type: "warn", Message: fmt.Sprint(args...), } addLogItem(l) } func Warnf(format string, args ...interface{}) { logger.Warnf(format, args...) l := &LogItem{ Type: "warn", Message: fmt.Sprintf(format, args...), } addLogItem(l) } func Error(args ...interface{}) { logger.Error(args...) l := &LogItem{ Type: "error", Message: fmt.Sprint(args...), } addLogItem(l) } func Errorf(format string, args ...interface{}) { logger.Errorf(format, args...) l := &LogItem{ Type: "error", Message: fmt.Sprintf(format, args...), } addLogItem(l) } func Fatal(args ...interface{}) { logger.Fatal(args...) } func Fatalf(format string, args ...interface{}) { logger.Fatalf(format, args...) } // Userf logs a user operation to the user log. func Userf(user string, action string, format string, args ...interface{}) { prefix := fmt.Sprintf("%s: %s - ", user, action) userLogger.Infof(prefix+format, args...) } ================================================ FILE: pkg/logger/otel.go ================================================ package logger import ( "context" "log" "github.com/stashapp/stash-box/internal/config" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/exporters/otlp/otlptrace" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" "go.opentelemetry.io/otel/sdk/resource" sdktrace "go.opentelemetry.io/otel/sdk/trace" ) func InitTracer() func(context.Context) error { otelConfig := config.GetOTelConfig() if otelConfig == nil { return nil } exporter, err := otlptrace.New( context.Background(), otlptracegrpc.NewClient( otlptracegrpc.WithInsecure(), otlptracegrpc.WithEndpoint(otelConfig.Endpoint), ), ) if err != nil { log.Fatal(err) } resources, err := resource.New( context.Background(), resource.WithAttributes( attribute.String("service.name", config.GetTitle()), attribute.String("library.language", "go"), ), ) if err != nil { log.Print("Could not set resources: ", err) } otel.SetTracerProvider( sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.TraceIDRatioBased(otelConfig.TraceRatio)), sdktrace.WithBatcher(exporter), sdktrace.WithResource(resources), ), ) logger.Infof("otel initialized with collector: %s, ratio: %f", otelConfig.Endpoint, otelConfig.TraceRatio) return exporter.Shutdown } ================================================ FILE: pkg/logger/progress_formatter.go ================================================ package logger import ( "github.com/sirupsen/logrus" ) type ProgressFormatter struct{} func (f *ProgressFormatter) Format(entry *logrus.Entry) ([]byte, error) { msg := []byte("Processing --> " + entry.Message + "\r") return msg, nil } ================================================ FILE: pkg/utils/arguments.go ================================================ // nolint: revive package utils import ( "context" "github.com/99designs/gqlgen/graphql" ) // https://github.com/99designs/gqlgen/issues/866#issuecomment-737684323 type argumentSelector = func(v interface{}) (ret interface{}, ok bool) // ArgumentsQuery to check whether arg value is null type ArgumentsQuery struct { args map[string]interface{} selectors []argumentSelector } func (a ArgumentsQuery) selected() (ret interface{}, ok bool) { ret, ok = a.args, true for _, fn := range a.selectors { ret, ok = fn(ret) if !ok { break } } return } // IsNull return whether selected field value is null. func (a ArgumentsQuery) IsNull() bool { v, ok := a.selected() return ok && v == nil } func (a ArgumentsQuery) child(fn argumentSelector) ArgumentsQuery { var selectors = make([]argumentSelector, 0, len(a.selectors)+1) selectors = append(selectors, a.selectors...) selectors = append(selectors, fn) return ArgumentsQuery{ args: a.args, selectors: selectors, } } // Field select field by name, returns a new query. func (a ArgumentsQuery) Field(name string) ArgumentsQuery { return a.child(func(v interface{}) (ret interface{}, ok bool) { var m map[string]interface{} if m, ok = v.(map[string]interface{}); ok { ret, ok = m[name] } return }) } // Index select field by array index, returns a new query. func (a ArgumentsQuery) Index(index int) ArgumentsQuery { return a.child(func(v interface{}) (ret interface{}, ok bool) { if index < 0 { return } var a []interface{} if a, ok = v.([]interface{}); ok { if index > len(a)-1 { ok = false return } ret = a[index] } return }) } // Arguments query to check whether args value is null. // https://github.com/99designs/gqlgen/issues/866 func Arguments(ctx context.Context) (ret ArgumentsQuery) { fc := graphql.GetFieldContext(ctx) oc := graphql.GetOperationContext(ctx) if fc == nil || oc == nil { return } ret.args = fc.Field.ArgumentMap(oc.Variables) return } ================================================ FILE: pkg/utils/crypto.go ================================================ // nolint: revive package utils import ( "crypto/rand" "encoding/ascii85" "fmt" "strconv" ) func GenerateRandomPassword(l int) (string, error) { b := make([]byte, l) if _, err := rand.Read(b); err != nil { return "", err } output := make([]byte, ascii85.MaxEncodedLen(l)) n := ascii85.Encode(output, b) output = output[0:n] return string(output), nil } func GenerateRandomKey(l int) (string, error) { b := make([]byte, l) if _, err := rand.Read(b); err != nil { return "", err } return fmt.Sprintf("%x", b), nil } // ParseFingerprintHash converts a fingerprint hash hex string to int64. func ParseFingerprintHash(hash string) (int64, error) { hashUint, err := strconv.ParseUint(hash, 16, 64) if err != nil { return 0, err } return int64(hashUint), nil } ================================================ FILE: pkg/utils/date.go ================================================ package utils import ( "fmt" "time" ) func ParseDateStringAsTime(dateString string) (time.Time, error) { switch len(dateString) { case 4: t, e := time.Parse("2006", dateString) if e == nil { return t, nil } case 7: t, e := time.Parse("2006-01", dateString) if e == nil { return t, nil } default: t, e := time.Parse("2006-01-02", dateString) if e == nil { return t, nil } } return time.Time{}, fmt.Errorf("ParseDateStringAsTime failed: dateString <%s>", dateString) } ================================================ FILE: pkg/utils/enum.go ================================================ // nolint: revive package utils import ( "reflect" ) type validator interface { IsValid() bool } func validateEnum(value interface{}) bool { v, ok := value.(validator) if !ok { // shouldn't happen return false } return v.IsValid() } func ResolveEnumString(value string, out interface{}) bool { if value == "" { return false } outValue := reflect.ValueOf(out).Elem() outValue.SetString(value) return validateEnum(out) } ================================================ FILE: pkg/utils/file.go ================================================ // nolint: revive package utils import ( "os" ) // FileExists returns true if the given path exists func FileExists(path string) (bool, error) { _, err := os.Stat(path) switch { case err == nil: return true, nil case os.IsNotExist(err): return false, err default: panic(err) } } // Touch creates an empty file at the given path if it doesn't already exist func Touch(path string) error { var _, err = os.Stat(path) if os.IsNotExist(err) { var file, err = os.Create(path) if err != nil { return err } return file.Close() } return nil } ================================================ FILE: pkg/utils/json.go ================================================ // nolint: revive package utils import ( "bytes" "encoding/json" ) func ToJSON(data interface{}) (json.RawMessage, error) { buffer := &bytes.Buffer{} encoder := json.NewEncoder(buffer) encoder.SetEscapeHTML(false) encoder.SetIndent("", " ") if err := encoder.Encode(data); err != nil { return nil, err } return buffer.Bytes(), nil } func FromJSON(data json.RawMessage, obj interface{}) error { return json.Unmarshal(data, obj) } ================================================ FILE: pkg/utils/password_blacklist.go ================================================ //nolint:misspell,revive package utils var bannedPasswordsSet = makeBannedPasswordsSet() // IsBannedPassword returns true if the password matches one from the banned // password list. func IsBannedPassword(password string) bool { // look for the password in the banned list _, found := bannedPasswordsSet[password] return found } func makeBannedPasswordsSet() map[string]struct{} { // this list was derived from the 10-million-password-list-top-100000.txt file in: // https://github.com/danielmiessler/SecLists/tree/master/Passwords/Common-Credentials // the list was filtered to the top 10,000 passwords over 8 characters long // grep -x '.\{8,\}' 10-million-password-list-top-100000.txt | head -n 10000 bannedPasswordsList := []string{ "password", "12345678", "123456789", "baseball", "football", "qwertyuiop", "1234567890", "superman", "1qaz2wsx", "trustno1", "jennifer", "sunshine", "iloveyou", "starwars", "computer", "michelle", "11111111", "princess", "987654321", "corvette", "1234qwer", "88888888", "q1w2e3r4t5", "internet", "samantha", "whatever", "maverick", "steelers", "mercedes", "123123123", "qwer1234", "hardcore", "q1w2e3r4", "midnight", "bigdaddy", "victoria", "1q2w3e4r", "cocacola", "marlboro", "asdfasdf", "87654321", "12344321", "jordan23", "Password", "jonathan", "liverpoo", "danielle", "abcd1234", "scorpion", "qazwsxedc", "password1", "slipknot", "qwerty123", "startrek", "12341234", "redskins", "butthead", "asdfghjkl", "qwertyui", "liverpool", "dolphins", "nicholas", "elephant", "mountain", "xxxxxxxx", "1q2w3e4r5t", "metallic", "shithead", "benjamin", "creative", "rush2112", "asdfghjk", "4815162342", "passw0rd", "bullshit", "1qazxsw2", "garfield", "01012011", "69696969", "december", "11223344", "godzilla", "airborne", "lifehack", "brooklyn", "platinum", "darkness", "blink182", "789456123", "12qwaszx", "snowball", "pakistan", "redwings", "williams", "nintendo", "guinness", "november", "minecraft", "asdf1234", "lasvegas", "babygirl", "dickhead", "12121212", "147258369", "explorer", "snickers", "metallica", "alexande", "paradise", "michigan", "carolina", "lacrosse", "christin", "kimberly", "kristina", "0987654321", "poohbear", "bollocks", "qweasdzxc", "drowssap", "caroline", "einstein", "spitfire", "maryjane", "1232323q", "champion", "svetlana", "westside", "courtney", "12345qwert", "patricia", "aaaaaaaa", "anderson", "security", "stargate", "simpsons", "scarface", "123456789a", "1234554321", "cherokee", "Usuckballz1", "veronica", "semperfi", "scotland", "marshall", "qwerty12", "98765432", "softball", "passport", "franklin", "alexander", "55555555", "zaq12wsx", "infinity", "kawasaki", "77777777", "vladimir", "freeuser", "wildcats", "budlight", "brittany", "00000000", "bulldogs", "swordfis", "PASSWORD", "patriots", "pearljam", "colorado", "ncc1701d", "motorola", "logitech", "juventus", "wolverin", "warcraft", "hello123", "peekaboo", "123654789", "panthers", "elizabet", "spiderma", "virginia", "valentin", "predator", "mitchell", "741852963", "1111111111", "rolltide", "changeme", "lovelove", "fktrcfylh", "loverboy", "chevelle", "cardinal", "michael1", "147852369", "american", "alexandr", "electric", "wolfpack", "spiderman", "darkside", "123456789q", "01011980", "freepass", "99999999", "fyfcnfcbz", "airplane", "22222222", "1029384756", "cheyenne", "billybob", "lawrence", "pussycat", "01012000", "chocolat", "business", "cjkysirj", "123qweasd", "stingray", "serenity", "greenday", "charlie1", "firebird", "blizzard", "a1b2c3d4", "sterling", "password123", "hercules", "tarheels", "remember", "basketball", "zeppelin", "swimming", "pavilion", "engineer", "bobafett", "21122112", "darkstar", "icecream", "hellfire", "fireball", "rockstar", "defender", "swordfish", "airforce", "abcdefgh", "srinivas", "bluebird", "presario", "wrangler", "precious", "harrison", "goldfish", "Soso123aljg", "dbrnjhbz", "thailand", "longhorn", "123qweasdzxc", "wordpass", "31415926", "999999999", "letmein1", "assassin", "testtest", "microsoft", "devildog", "valentina", "butterfly", "lonewolf", "babydoll", "atlantis", "montreal", "angelina", "shamrock", "hotstuff", "mistress", "deftones", "cadillac", "blahblah", "birthday", "1234abcd", "01011990", "cavalier", "veronika", "qazwsx123", "mustang1", "goldberg", "12345678910", "wolfgang", "savannah", "leonardo", "basketba", "cristina", "aardvark", "sweetpea", "13131313", "freedom1", "fredfred", "manchester", "kathleen", "hamilton", "fuckyou2", "renegade", "drpepper", "bigboobs", "1qaz2wsx3edc", "christia", "buckeyes", "0123456789", "stephani", "enterpri", "diamonds", "wetpussy", "morpheus", "66666666", "pornstar", "thuglife", "napoleon", "highland", "chandler", "trfnthbyf", "consumer", "welcome1", "123qwe123", "wrinkle1", "51505150", "11235813", "butterfl", "elizabeth", "sherlock", "marathon", "access14", "overlord", "trombone", "isabelle", "barcelona", "babylon5", "ultimate", "yankees1", "superfly", "campbell", "geronimo", "concrete", "q1w2e3r4t5y6", "jessica1", "123454321", "portugal", "sundance", "pleasure", "seminole", "isabella", "14789632", "qazxswedc", "kingkong", "adgjmptw", "ncc1701e", "mongoose", "alejandr", "1123581321", "margaret", "bluemoon", "ghbdtnbr", "bonehead", "stallion", "personal", "morrison", "super123", "anything", "aleksandr", "rhbcnbyf", "dietcoke", "cooldude", "christop", "lollipop", "fernando", "christian", "letmein2", "01012010", "werewolf", "punkrock", "giovanni", "cdtnkfyf", "tottenha", "hongkong", "blackcat", "a1234567", "zzzzzzzz", "hollywoo", "florence", "gn56gn56", "clifford", "stocking", "matthew1", "immortal", "44444444", "makaveli", "sebastia", "ilovesex", "charlott", "anthony1", "111222333", "satan666", "columbia", "infantry", "eternity", "waterloo", "vanhalen", "skywalke", "seinfeld", "standard", "squirrel", "qazwsxed", "fuckfuck", "wolverine", "robinson", "musicman", "megadeth", "verbatim", "1q2w3e4r5t6y", "twilight", "fuckyou1", "stardust", "showtime", "147896325", "skittles", "shaney14", "qwerty12345", "123321123", "intrepid", "sandiego", "punisher", "1234567a", "dingdong", "192837465", "starcraft", "mushroom", "blackdog", "25802580", "slapshot", "ekaterina", "123698745", "1234512345", "chargers", "33333333", "warriors", "raistlin", "gangster", "coltrane", "tacobell", "portland", "penelope", "1a2b3c4d", "19841984", "12369874", "stranger", "Mailcreated5240", "halflife", "qwerasdf", "playtime", "kangaroo", "blackman", "panasonic", "christine", "beautiful", "spanking", "meridian", "lonestar", "kittycat", "goodluck", "barcelon", "scoobydo", "crusader", "12312312", "hannibal", "guardian", "fuckface", "discover", "catalina", "1122334455", "californ", "angelica", "william1", "stonecol", "johnjohn", "septembe", "scarlett", "santiago", "lowrider", "anastasia", "vacation", "sithlord", "ragnarok", "keyboard", "19921992", "11112222", "penguins", "nuttertools", "lorraine", "dkflbvbh", "titleist", "rootbeer", "magnolia", "dodgeram", "creampie", "aspirine", "socrates", "1234567q", "redalert", "qqqqqqqq", "munchkin", "mersedes", "imperial", "blueeyes", "bigballs", "zaq1xsw2", "sebastian", "research", "national", "colombia", "01012001", "rammstein", "katerina", "freckles", "caliente", "director", "qazwsxedcrfv", "oblivion", "mustangs", "margarita", "deadhead", "zxcv1234", "porkchop", "grateful", "fuck_inside", "formula1", "a1s2d3f4", "23232323", "shopping", "peterpan", "martinez", "justdoit", "goodtime", "alexandra", "thankyou", "springer", "Software", "sapphire", "richmond", "kingston", "brucelee", "thunder1", "qawsedrf", "plymouth", "mariners", "heather1", "chelsea1", "123456qwerty", "spectrum", "pineappl", "labrador", "1234567890q", "10101010", "stephanie", "commando", "amsterdam", "webmaster", "southern", "lesbians", "fletcher", "thompson", "Passw0rd", "candyman", "aquarius", "starfish", "monopoly", "infiniti", "gangbang", "blackjac", "8J4yE3Uz", "19871987", "0000000000", "sailboat", "richard1", "godsmack", "emmanuel", "cosworth", "19891989", "rosemary", "lightnin", "chevrole", "catherin", "qwerty123456", "frontier", "asshole1", "01011991", "spartans", "luckydog", "15426378", "swingers", "snuggles", "qwertyuio", "qwert123", "mandingo", "ihateyou", "beefcake", "beatrice", "111111111", "whocares", "scooter1", "doberman", "clitoris", "5555555555", "dannyboy", "children", "viktoria", "valhalla", "terminator", "oklahoma", "ncc1701a", "keystone", "clarence", "bunghole", "19751975", "romashka", "pa55word", "golfball", "doughboy", "charlotte", "achilles", "patrick1", "gateway1", "deeznuts", "cowboys1", "9876543210", "vkontakte", "phillies", "jeremiah", "dilligaf", "atlantic", "19851985", "vfrcbvrf", "technics", "stripper", "september", "pinkfloy", "maryland", "kentucky", "hastings", "frederic", "butthole", "agent007", "19911991", "01011985", "somethin", "porsche9", "hurrican", "california", "bearbear", "73501505", "nathalie", "microlab", "function", "flamingo", "enterprise", "19941994", "19781978", "01011970", "truelove", "nebraska", "meatball", "brothers", "syracuse", "military", "macdaddy", "diamond1", "warhammer", "universe", "sentinel", "Password1", "manchest", "kamikaze", "handsome", "dthjybrf", "designer", "blueblue", "australia", "321654987", "1qaz1qaz", "01011981", "pokemon1", "pantyhos", "eatpussy", "19861986", "01011986", "superstar", "ssssssss", "rjirfrgbde", "meatloaf", "lifetime", "jamesbon", "123456789z", "woofwoof", "Turkey50", "rfnthbyf", "Jennifer", "front242", "apollo13", "terminal", "starbuck", "lancelot", "gordon24", "brandon1", "bigmoney", "azsxdcfv", "rightnow", "maradona", "lionking", "crazybab", "charlton", "19931993", "19901990", "poiuytrewq", "passwort", "japanese", "holyshit", "bradford", "21212121", "wildfire", "sexygirl", "poontang", "microsof", "chocolate", "chickens", "arsenal1", "19831983", "software", "happyday", "aberdeen", "19951995", "13243546", "123456aa", "treasure", "theodore", "raiders1", "gretchen", "ericsson", "albatros", "1Passwor", "0.0.0.000", "zxcasdqwe", "Sojdlg123aljg", "sexsexsex", "mikemike", "michaela", "jackson1", "excalibu", "anhyeuem", "78945612", "trinidad", "pooppoop", "greenbay", "greatone", "fordf150", "applepie", "963852741", "18436572", "lisalisa", "hardrock", "dinosaur", "rastaman", "pa55w0rd", "madeline", "hollywood", "hellyeah", "columbus", "skywalker", "rockhard", "positive", "melissa1", "kcj9wx5n", "hyperion", "happy123", "gotohell", "football1", "february", "abc12345", "609609609", "yosemite", "roadkill", "kingfish", "billyboy", "1qa2ws3ed", "123789456", "tunafish", "starship", "saratoga", "robotech", "rasputin", "rangers1", "passwords", "p0015123", "nwo4life", "megapass", "kenworth", "hedgehog", "davidson", "anaconda", "20102010", "12131415", "vladislav", "Translator", "splinter", "richards", "phoenix1", "karolina", "789789789", "railroad", "pingpong", "magicman", "killbill", "01011989", "wrestlin", "tommyboy", "sherwood", "passpass", "pass1234", "majestic", "fuckthis", "freeporn", "crawford", "bangbang", "asdasdasd", "umbrella", "salvador", "operator", "jeanette", "gggggggg", "fktrcfylhf", "deepthroat", "cinnamon", "chester1", "broadway", "01011988", "underdog", "sunnyday", "snoopdog", "multiplelo", "jasmine1", "Computer", "chemical", "chainsaw", "catherine", "canadian", "brighton", "australi", "alliance", "19721972", "19691969", "supersta", "snowboar", "r2d2c3po", "mechanic", "mamapapa", "golfgolf", "ghjcnjnfr", "downtown", "christopher", "chicken1", "bullseye", "20002000", "skorpion", "saturday", "peterson", "meredith", "lkjhgfdsa", "eastside", "blackhaw", "backdoor", "westwood", "sneakers", "Passwor1", "marino13", "jamesbond", "getmoney", "flounder", "boomboom", "beerbeer", "apple123", "01011987", "01011984", "undertaker", "sinclair", "samsung1", "moneyman", "mmmmmmmm", "marianne", "jjjjjjjj", "gargoyle", "federico", "amsterda", "1x2zkg8w", "19881988", "19741974", "zerocool", "vfvfgfgf", "test1234", "idontknow", "hahahaha", "cambiami", "a123456789", "19731973", "03082006", "02071986", "vfhufhbnf", "pppppppp", "motherlode", "lokomotiv", "kristine", "goldstar", "christina", "chrisbln", "america1", "20012001", "12345678q", "whitesox", "titanium", "thursday", "thirteen", "tazmania", "starfire", "qwerqwer", "qazwsx12", "panasoni", "paintbal", "newcastl", "hotpussy", "giuseppe", "buckshot", "babyblue", "attitude", "10203040", "01011910", "Superman", "sunflowe", "solution", "phillips", "knickers", "godfather", "clarinet", "assholes", "12345679", "tomorrow", "southpark", "sersolution", "rhfcjnrf", "qwerty1234", "paintball", "montgom240", "johannes", "intruder", "gesperrt", "francois", "dkflbckfd", "dfktynbyf", "christie", "callaway", "19821982", "19811981", "12qw34er", "123qwerty", "salamander", "resident", "poseidon", "pianoman", "chuckles", "avalanch", "1q2w3e4r5", "superman1", "rockford", "qwertyqwerty", "meowmeow", "meathead", "budweise", "19411945", "14725836", "01091989", "01011992", "triangle", "thanatos", "runescape", "gladiator", "crjhgbjy", "barefoot", "25252525", "02071982", "zxcvbnm1", "viewsonic", "traveler", "together", "spongebob", "original", "mohammed", "medicine", "mazafaka", "juliette", "james007", "hawkeyes", "deeznutz", "cerberus", "135792468", "12345qwe", "01234567", "01011975", "zxasqw12", "terrapin", "something", "philippe", "overkill", "monalisa", "illusion", "hoosiers", "hayabusa", "gfhjkm123", "francesc", "confused", "clevelan", "123456654321", "01011993", "tttttttt", "smeghead", "moonlight", "megatron", "cfitymrf", "casanova", "blackjack", "blablabla", "bbbbbbbb", "12301230", "syncmaster", "rhiannon", "lightning", "dddddddd", "brewster", "bookworm", "blessing", "babybaby", "aleksandra", "19961996", "19791979", "02091987", "02021987", "valencia", "thegreat", "packers1", "newpass6", "Michelle", "dutchess", "charles1", "alphabet", "19801980", "02081988", "02051986", "02041986", "02011985", "01011977", "roadrunn", "rjycnfynby", "rhtdtlrj", "mortgage", "goldwing", "christmas", "andromeda", "adrienne", "12345678a", "12011987", "02101985", "02031986", "02021988", "wrestling", "tinkerbell", "teddybea", "sinister", "shannon1", "motherfucker", "mortimer", "madison1", "handyman", "ghostrider", "doghouse", "balloons", "24682468", "02061985", "02011987", "wareagle", "roadking", "realmadrid", "PolniyPizdec0211", "nokia6300", "idontkno", "gameover", "claymore", "chicago1", "blackbir", "bcfields", "1357924680", "02091986", "02021986", "01011983", "whiskers", "valkyrie", "talisman", "starcraf", "sporting", "spaceman", "southpar", "lipstick", "kittykat", "inuyasha", "babyface", "7uGd5HIp2J", "02081987", "02081984", "02061986", "02021984", "01011982", "strength", "seahawks", "recovery", "qweqweqwe", "playstation", "leavemealone", "hardcock", "florida1", "flexible", "dragonball", "checkers", "charlene", "beautifu", "baseball1", "02031984", "02021985", "thedoors", "sullivan", "stanford", "mollydog", "illinois", "ghblehjr", "gamecube", "cannabis", "cameltoe", "bitchass", "armagedon", "alexalex", "987456321", "21031988", "123qq123", "1234567890a", "02081989", "02011986", "01020304", "01011999", "wishbone", "matthews", "mandarin", "lalalala", "godfathe", "gabriela", "ffffffff", "bluefish", "binladen", "19771977", "19761976", "02061989", "02041984", "tottenham", "tiberius", "teddybear", "silverad", "northern", "microphone", "electron", "dirtbike", "deadpool", "carpedie", "asdfzxcv", "amateurs", "absolute", "50spanks", "02021983", "vampires", "shanghai", "property", "password2", "netscape", "kakashka", "hawaiian", "gfhjkmgfhjkm", "fyutkbyf", "digital1", "caligula", "blackout", "15151515", "123456qw", "1234567891", "02051983", "02041983", "02031987", "02021989", "z1x2c3v4", "vSjasnel12", "testpass", "stonecold", "soulmate", "q2w3e4r5", "millions", "lineage2", "fuckoff1", "friendly", "fgtkmcby", "criminal", "coldbeer", "capslock", "bullfrog", "bobdylan", "babylove", "argentina", "annabell", "11221122", "02081986", "02041988", "02041987", "02041982", "02011988", "yeahbaby", "vasilisa", "sergeant", "reynolds", "newyork1", "magazine", "llllllll", "katherine", "jayhawks", "fishing1", "dragon12", "abnormal", "09876543", "02101984", "02081985", "02071984", "02011980", "01011979", "wg8e3wjf", "shitface", "salasana", "rebecca1", "pussyman", "pringles", "preacher", "heineken", "gatorade", "gabriell", "ferrari1", "eldorado", "coolness", "BASEBALL", "14141414", "02021982", "thunderb", "telephon", "specialk", "shepherd", "patience", "paranoid", "monster1", "missouri", "masamune", "mamamama", "laurence", "hopeless", "farscape", "estrella", "eastwood", "dragonba", "crystal1", "corleone", "chevrolet", "carlitos", "buttercu", "buddyboy", "24242424", "12365478", "02061988", "02031985", "yfcntymrf", "winston1", "slippery", "sandwich", "piramida", "monkey12", "millwall", "magician", "jackson5", "insomnia", "hardware", "fountain", "fastball", "elizaveta", "borussia", "andromed", "alejandro", "1234asdf", "02081982", "02051982", "windsurf", "wildcard", "universal", "sunflower", "strawberry", "reddevil", "pornporn", "polopolo", "pinkfloyd", "panther1", "jiggaman", "islander", "inspiron", "green123", "cristian", "1a2s3d4f", "123456qwe", "02061980", "02031982", "02011984", "zaqxswcde", "washington", "violetta", "smashing", "sexysexy", "robotics", "rjhjktdf", "reckless", "nightmare", "knockers", "killkill", "katherin", "jellybea", "hhhhhhhh", "gandalf1", "download", "doomsday", "devil666", "darklord", "classics", "chrysler", "browning", "barbados", "9293709b13", "20202020", "02091983", "02061987", "01081989", "yjdsqgfhjkm", "snowboard", "scrabble", "rhjrjlbk", "rainbow6", "qazwsxedc123", "pharmacy", "nevermind", "mariposa", "jakejake", "insanity", "graphics", "geoffrey", "firewall", "fandango", "augustus", "ashleigh", "321321321", "12051988", "05051987", "02101989", "02101987", "02071987", "02071980", "02041985", "sweetnes", "stanislav", "scorpio1", "rochelle", "radiohea", "pumpkins", "mobydick", "longjohn", "iverson3", "istanbul", "highheel", "happiness", "gamecock", "faithful", "creature", "creation", "concorde", "budapest", "19711971", "134679852", "02091984", "02091981", "02091980", "02061983", "02041981", "01011900", "windmill", "webhompas", "thisisit", "spongebo", "senators", "sausages", "pineapple", "nygiants", "moonbeam", "marcello", "maksimka", "loveless", "lollypop", "kleopatra", "katarina", "icehouse", "hooligan", "gertrude", "fullmoon", "fuckinside", "dynamite", "buttfuck", "bulldog1", "brittney", "aviation", "22041987", "20022002", "05051985", "02081977", "02071988", "02051988", "02051987", "02041979", "webmaste", "radiohead", "platypus", "monkeybo", "Michael1", "master12", "heritage", "Good123654", "festival", "evolution", "dolphin1", "cccccccc", "a12345678", "26061987", "15051981", "08031986", "02061984", "02061982", "02051989", "02051984", "02031981", "woodland", "whiteout", "vanguard", "temppass", "reddwarf", "pussy123", "forsaken", "Football", "ferguson", "earnhard", "coolcool", "7894561230", "21031987", "13041988", "11051987", "10011986", "06061986", "02091985", "02021981", "02021979", "01031988", "tiger123", "summer99", "starstar", "snowflak", "slamdunk", "playboy1", "michael2", "mephisto", "kkkkkkkk", "kjrjvjnbd", "killer12", "iloveyou2", "holidays", "harrypotter", "gorgeous", "dudedude", "andersen", "02101986", "02081983", "02041989", "02011989", "01011978", "zxcvbnm123", "volkswag", "solitude", "scoobydoo", "roadster", "presiden", "pool6123", "playstat", "pipeline", "mypassword", "mazdarx7", "lemonade", "krasotka", "koroleva", "irishman", "hawaii50", "gabriel1", "freefree", "francesco", "christma", "chipmunk", "brigitte", "bigblock", "bergkamp", "bearcats", "74108520", "45M2DO5BS", "30051985", "24061986", "22021989", "21011989", "20061988", "1z2x3c4v", "14061991", "13041987", "12021988", "11081989", "03041991", "02071981", "02031979", "02021976", "01061990", "01011960", "yankees2", "wireless", "tiffany1", "starligh", "register", "pallmall", "nascar24", "mudvayne", "monsters", "mckenzie", "mazda626", "kisskiss", "gonzalez", "gbhfvblf", "freebird", "fantasia", "comanche", "choochoo", "chambers", "borabora", "asdfgh01", "alessandro", "abrakadabra", "7777777777", "23456789", "23041987", "19701970", "18011987", "123456789s", "07071987", "02091989", "02071989", "02071983", "02021973", "02011981", "01121986", "01071986", "yogibear", "wanderer", "viktoriya", "undertak", "underground", "tropical", "threesom", "slowhand", "sheridan", "marianna", "kissmyass", "just4fun", "ghjcnjgfhjkm", "FOOTBALL", "fishhead", "firefire", "excalibur", "customer", "cocksuck", "cameron1", "berkeley", "andyod22", "28041987", "25081988", "24011985", "20111986", "19651965", "19101987", "19061987", "14111986", "13031987", "123456123", "12121990", "10071987", "10031988", "02101988", "02081980", "02021990", "01091987", "01041985", "01011995", "zanzibar", "training", "sweetness", "president", "password12", "lovelife", "longdong", "johndeer", "jefferso", "james123", "jackjack", "fishbone", "drummer1", "coventry", "catwoman", "28021992", "25800852", "22011988", "19971997", "17051988", "14021985", "13061986", "12121985", "11061985", "10101986", "10051987", "10011990", "09051945", "08121986", "04041991", "03041986", "02101983", "02101981", "02031989", "02031980", "01121988", "survivor", "sundevil", "straight", "revolver", "qwerty11", "qweasd123", "paradigm", "nonenone", "michaels", "ghjuhfvvf", "fairlane", "everlast", "chestnut", "broncos1", "antelope", "anastasiya", "456456456", "30041986", "29071983", "29051989", "29011985", "28021990", "28011987", "27061988", "25121987", "25031987", "22021986", "21031990", "20091991", "20031987", "19681968", "17061988", "16051989", "16051987", "11051990", "08051990", "05051989", "04041988", "02051980", "02051976", "02041980", "02031977", "02011983", "01061986", "01041988", "01011994", "zxcasdqwe123", "washburn", "vfitymrf", "soccer12", "soccer10", "smirnoff", "sasha_007", "rrrrrrrr", "qwert12345", "pumpkin1", "porsche1", "noname123", "newcastle", "marseille", "marjorie", "hurricane", "honolulu", "highbury", "gilligan", "eeeeeeee", "death666", "costello", "baritone", "31011987", "30031988", "22071986", "21101986", "21051991", "20091988", "20051988", "19661966", "18091985", "18061990", "15101986", "15051990", "15011987", "13121985", "12qw12qw", "12031987", "12031985", "11121986", "08081988", "08031985", "03031986", "02101979", "02071979", "02071978", "02051985", "02051978", "02051973", "02041975", "02041974", "02031988", "02011982", "01031989", "01011974", "wwwwwwww", "wildwood", "wildbill", "superior", "stefanie", "sidekick", "remingto", "redbaron", "question", "moonligh", "mischief", "ministry", "minemine", "Kordell1", "knuckles", "fuckhead", "freefall", "fantomas", "elcamino", "coldplay", "clippers", "carpente", "capricorn", "calimero", "bluesman", "bluebell", "Baseball", "armstron", "angelika", "angel123", "30041987", "27081990", "26031988", "25091987", "25041988", "24111989", "23021986", "22041988", "22031984", "21051988", "17011987", "16121987", "15021985", "14021986", "13021990", "123456ru", "10101990", "10041986", "07091990", "02051981", "01031985", "01021990", "zildjian", "WP2003WP", "valentine", "trinitro", "swinging", "rfvfcenhf", "pufunga7782", "palmtree", "nostromo", "johngalt", "iloveyou1", "foxylady", "fishfish", "fearless", "enforcer", "david123", "cutiepie", "cheshire", "cherries", "capricor", "blueball", "blowfish", "31031988", "25091990", "25011990", "24111987", "23031990", "22061988", "21011991", "21011988", "19283746", "19031985", "19011989", "18091986", "17111985", "16051988", "15071987", "14081985", "13071984", "12081985", "11021985", "10071988", "09021988", "05061990", "02051972", "02041978", "02031983", "01091985", "01031984", "01012009", "yamahar1", "whistler", "vjqgfhjkm", "universa", "strawber", "sprinter", "spencer1", "sonyfuck", "slimshady", "screamer", "Princess", "papillon", "oooooooo", "Maverick", "marcius2", "lalakers", "lakeside", "jermaine", "honeybee", "highlander", "ghbywtccf", "ghbdtn123", "earthlink", "cygnusx1", "cleopatr", "carnival", "buddy123", "arkansas", "anastasi", "30081984", "25101988", "23051985", "23041986", "23021989", "22121987", "22091988", "22071987", "22021988", "20052005", "19051987", "15041988", "15011985", "14021990", "14011986", "13051987", "13011988", "13011987", "12061988", "12041988", "12041986", "11071988", "11031988", "10081989", "08081986", "07071990", "07071977", "05071984", "04041983", "03021986", "02091988", "02081976", "02051977", "02031978", "01071987", "01041987", "01011976", "zachary1", "wrestler", "vendetta", "tkbpfdtnf", "terminat", "telephone", "smackdow", "sandrine", "qwe123qwe", "opendoor", "nautilus", "mustang6", "Misfit99", "marseill", "magellan", "Letmein1", "leedsutd", "jackass1", "hounddog", "hetfield", "gtnhjdbx", "ghhh47hj7649", "fkbyjxrf", "espresso", "dontknow", "dogpound", "complete", "bismillah", "argentin", "30041985", "29071985", "29061990", "27071987", "27061985", "27041990", "26031990", "24031988", "23051990", "22011986", "21061986", "20121989", "20092009", "20091986", "20081991", "20041988", "20041986", "19671967", "19121989", "19061990", "18101987", "18051988", "18041986", "18021984", "17101986", "17061989", "17041991", "16021990", "15071988", "15071986", "14101987", "135798642", "13061987", "1234zxcv", "12071989", "11121985", "11061991", "10121987", "10101985", "10031987", "09041987", "09031988", "06041988", "05071988", "03081989", "02071985", "02071975", "01051989", "01041992", "01041990", "whiteboy", "waterboy", "vikings1", "viewsoni", "penguin1", "Password123", "optimist", "moonshin", "mcdonald", "limewire", "konstantin", "jonathon", "johncena", "intercourse", "harddick", "gladiato", "fortress", "clarissa", "capetown", "camaross", "callisto", "bigpoppa", "alexandre", "9999999999", "30011985", "29051985", "26061985", "25111987", "25071990", "22081986", "22061989", "21061985", "20082008", "20021988", "19981998", "16051985", "15111988", "15051985", "15021990", "14041988", "12345qwerty", "12121988", "12051990", "12051986", "12041990", "11091989", "11051986", "11051984", "10061986", "06081987", "06021987", "04041990", "02081981", "02061977", "02041977", "02031975", "01121987", "01061988", "01031986", "01021989", "01021988", "university", "trucking", "transfer", "tomahawk", "suckmydick", "suburban", "stratfor", "shadow12", "private1", "printing", "pentagon", "notebook", "nokian73", "matthias", "marijuan", "mandrake", "mamacita", "kayleigh", "hotgirls", "hellokitty", "hallo123", "funstuff", "fredrick", "firefigh", "eggplant", "dfktynby", "derparol", "cleopatra", "cbr900rr", "barselona", "asdqwe123", "almighty", "absolutely", "29061989", "28051987", "27081986", "25061985", "25011986", "24091986", "24061988", "24031990", "21081987", "21041992", "20031991", "19061985", "18111987", "18021988", "17071989", "17031987", "16051990", "15021986", "14031988", "14021987", "14011989", "11011990", "10011983", "09021989", "07051990", "06051986", "05091988", "05081988", "04061986", "04041985", "03041980", "02101976", "02071976", "02061976", "02011975", "01031983", "washingt", "warrior1", "username", "Trustno1", "tinkerbe", "suckdick", "southpaw", "sexylady", "rocknrol", "rfhnjirf", "progress", "obsidian", "nirvana1", "nineinch", "navigator", "money123", "modelsne", "minimoni", "millenium", "marriage", "marines1", "marijuana", "htubcnhfwbz", "heinrich", "handball", "facebook", "dominion", "darkangel", "cricket1", "chris123", "challeng", "bubba123", "bluejays", "antonina", "28051986", "28021985", "27031989", "26021987", "25101989", "25061986", "25041985", "25011985", "24061987", "23021985", "23011985", "22121986", "22121983", "22081983", "22071989", "22061987", "22061941", "22041986", "22021985", "21021985", "20031988", "19101990", "19071988", "19071986", "18061985", "18051990", "17071985", "16111990", "16061986", "16011989", "15081991", "15051987", "14071987", "13031986", "12101988", "12081984", "12071987", "11121987", "11081987", "11071985", "11011991", "08071987", "08061987", "05061986", "04061991", "03111987", "03071987", "02091976", "02081979", "02041976", "02031973", "02021991", "02021980", "02021971", "whatwhat", "Welcome1", "VQsaBLPzLa", "theforce", "sylveste", "stephane", "sheepdog", "services", "roadrunner", "republic", "paramedi", "masterbate", "margarit", "ilikepie", "homework", "hattrick", "hardball", "goodgirl", "friendster", "flipflop", "f00tball", "evolutio", "dukeduke", "cucumber", "cnfybckfd", "chiquita", "castillo", "bigdicks", "31121990", "30121987", "29121987", "29111989", "29081990", "29081985", "29051990", "27272727", "27091985", "27031987", "26031987", "26031984", "24051990", "23061990", "22061990", "22041985", "22031991", "22021990", "21111985", "21041985", "20021986", "19071990", "19051986", "19011987", "17171717", "17061986", "17041987", "16101987", "16031990", "15091987", "15081988", "15071985", "15011986", "14101988", "14071988", "14051990", "14021983", "13111990", "12121987", "12121982", "12061986", "12011989", "11111987", "11081990", "10111986", "10031991", "09090909", "08051987", "08041986", "05051990", "04081987", "04051988", "03061987", "03031993", "03031988", "02101980", "02101977", "02091977", "02091975", "02061979", "02051975", "01081990", "01061987", "01011971", "toriamos", "taekwondo", "sonyericsson", "slimshad", "skateboard", "riccardo", "rfntymrf", "prospect", "penetration", "peaches1", "nokia6233", "nightwish", "Mercedes", "maxwell1", "mash4077", "lakewood", "krokodil", "hairball", "evangelion", "dolemite", "cromwell", "cassandr", "cabernet", "budweiser", "bastards", "azertyui", "aolsucks", "45454545", "31011990", "29011987", "28071986", "28021986", "27051987", "27011988", "26051988", "26041991", "26041986", "25011993", "24121986", "24061992", "24021991", "24011990", "23051986", "23021988", "23011990", "21121986", "21111990", "21071989", "20071986", "20051985", "20011989", "19111987", "19091988", "18041990", "18021986", "18011986", "17101987", "17091987", "17021985", "17011990", "16061985", "15051986", "14881488", "14121989", "14081988", "14071986", "13111984", "12121989", "12101985", "12051985", "11071986", "11011987", "10293847", "10081985", "10061987", "10041983", "07091982", "07081986", "06061987", "06041987", "06031983", "04091986", "03071986", "03051987", "03051986", "03031990", "03011987", "02101978", "02091973", "02081974", "02071977", "02071971", "0192837465", "01051988", "01051986", "01011973", "Victoria", "vauxhall", "vancouve", "touching", "tokiohotel", "supernov", "speakers", "spartan1", "sigmachi", "rocknroll", "rainyday", "q123456789", "puppydog", "power123", "poiuytre", "phialpha", "penthous", "pavement", "nthvbyfnjh", "nnnnnnnn", "mulligan", "mississippi", "lonesome", "lighting", "klondike", "kazantip", "ironmaiden", "homemade", "herewego", "gonzales", "goldfing", "genesis1", "fyfnjkbq", "forgetit", "flamengo", "favorite6", "exchange", "enternow", "dodgers1", "delaware", "darkange", "commande", "cashmone", "bordeaux", "billabon", "benessere", "awesome1", "asdffdsa", "archange", "annmarie", "ambrosia", "alleycat", "aaaaaaaaaa", "43214321", "369258147", "31121988", "31121987", "30061987", "30011986", "29041985", "28121984", "28061986", "28041992", "28031982", "27111985", "27021991", "26111985", "26101986", "26091986", "26031986", "25021988", "24111990", "24101986", "24071987", "24011987", "23051991", "23051987", "23031987", "22071983", "22051986", "21101989", "21071987", "21051986", "20081986", "20061986", "20031986", "20021985", "20011988", "19641964", "19111986", "19101986", "19021990", "18051987", "18031991", "18021987", "16111982", "16011987", "15111984", "15091988", "15061988", "15031988", "15021983", "14021989", "14011988", "14011987", "12348765", "12345qaz", "12111990", "12091988", "12051989", "12051987", "12031988", "12021985", "12011985", "11111986", "11091984", "11071989", "10071985", "10061984", "10041990", "10031989", "10011988", "06071983", "05021988", "03041987", "02091982", "02091971", "02061974", "02051990", "02051979", "02011990", "01051990", "01021985", "woodstoc", "wonderful", "whiplash", "trouble1", "testing1", "summer69", "stickman", "stafford", "speedway", "somerset", "smoothie", "segblue2", "scheisse", "Samantha", "revolution", "rainbows", "pornking", "pimpdadd", "pasadena", "p0o9i8u7", "navyseal", "Marlboro", "longhair", "lokiloki", "lkjhgfds", "kamasutra", "gsxr1000", "gannibal", "daylight", "cornwall", "cocksucker", "carebear", "austin31", "adrenalin", "789654123", "5Wr2i7H8", "31031987", "30111987", "30071986", "30061983", "30051989", "30041991", "28071987", "28051990", "28051985", "27041985", "26071987", "26061986", "26051986", "25121985", "25051985", "24081988", "24041988", "24031987", "24021988", "23skidoo", "23121986", "23091987", "23071985", "23061992", "22111985", "22091986", "22081991", "22071990", "22061985", "21081985", "21071992", "21021987", "20101988", "20061984", "20051989", "20041990", "19091990", "19031987", "18121984", "18081988", "18061991", "18041991", "18011988", "17061991", "17021987", "16031988", "16021987", "15091989", "15081990", "15071983", "15041987", "14091990", "14081990", "14041992", "14041987", "14031989", "13081985", "13021987", "123qwert", "12345qwer", "12345abc", "123456789m", "1212121212", "12081983", "12021991", "11101986", "11081988", "11061989", "11041991", "11011989", "10121986", "10121985", "10101989", "10041991", "09091986", "09081988", "09051986", "08071988", "08011986", "07101987", "07071985", "06061985", "06011988", "05031991", "05021987", "04061984", "04051985", "02101973", "02061981", "02061972", "02041973", "02011979", "01101987", "01051985", "01021987", "wonderboy", "voyager1", "vagabond", "toonarmy", "thrasher", "stigmata", "smackdown", "sexybabe", "sergbest", "scrapper", "sammy123", "reginald", "rainbow1", "pictures", "peterbil", "perfect1", "pantera1", "p4ssw0rd", "normandy", "nevermore", "luckyone", "kirkland", "junkmail", "josephin", "Jordan23", "johnson1", "futurama", "fireblad", "fellatio", "dragonfl", "dragon69", "crackers", "cartoons", "buttercup", "blue1234", "31101987", "31051985", "30121986", "30091989", "30031992", "30031986", "30011987", "29061988", "29061985", "29031988", "28061988", "27061983", "27031986", "27021990", "26101987", "26071989", "26071986", "25081986", "25061987", "25051987", "25041991", "24101989", "24071991", "23111987", "23091986", "23051983", "23031986", "2222222222", "22121989", "22071991", "22051991", "22011985", "21121985", "21031985", "20121988", "20121986", "20061990", "20051987", "19091983", "19061992", "19021991", "18121987", "18121983", "18111986", "16121986", "16091987", "16071991", "16071987", "15111989", "15031990", "14041986", "13121983", "13101987", "13091984", "13071990", "123456789qwe", "1234567899", "12211221", "12121991", "12121986", "12101990", "12101984", "12091991", "12081988", "12071990", "12071988", "11041990", "10081990", "10081983", "10071990", "10061989", "10011992", "09111987", "09081985", "08121987", "08111984", "08101986", "08051989", "07091988", "07081987", "07071988", "07071984", "07071982", "07051987", "06031992", "05111986", "05051991", "05031990", "05011987", "04111988", "04061987", "04041987", "02081973", "02061978", "02031991", "02031990", "02011976", "01071984", "01041980", "01021992", "zaqwsxcde", "yyyyyyyy", "warhamme", "velocity", "tigercat", "sunlight", "streaming", "sonysony", "sabrina1", "romantic", "rockwell", "q1234567", "plastics", "pinnacle", "pathetic", "pancakes", "offshore", "nounours", "ncc74656", "natasha1", "mynameis", "motocros", "letsdoit", "kristian", "fyutkjxtr", "francisc", "dreamcas", "dragster", "destiny1", "delpiero", "daisydog", "colonial", "cannibal", "candyass", "bynthytn", "bigbooty", "azertyuiop", "amethyst", "acidburn", "66613666", "44332211", "31071990", "31051993", "30051987", "30011990", "29091987", "29061986", "29011982", "28101986", "28081990", "28081986", "28011988", "27111989", "27031992", "27021992", "26081986", "25081985", "25031991", "25031983", "24121987", "24091991", "23111989", "23091989", "23091985", "23061989", "22091991", "22071985", "22071984", "22061984", "22051989", "22051987", "22031986", "22011992", "21061988", "21031984", "20071988", "20061983", "20041985", "1qazzaq1", "1qazxsw23edc", "19991999", "19061991", "18101985", "18051989", "18031988", "18021992", "18011985", "17051990", "17051989", "17051987", "17021989", "16091988", "16081986", "16061988", "16061987", "15121987", "15091985", "15081986", "15061985", "15011983", "14101986", "13071987", "13061985", "13021985", "123456qqq", "123456789d", "1234509876", "12131213", "12111991", "12111985", "12081990", "12081987", "12071991", "11071987", "11051988", "11031983", "10091984", "10071989", "10071986", "10061985", "10051990", "10041987", "10031993", "10031990", "09091988", "09051987", "09041986", "08081990", "08081989", "08021990", "07101984", "07071989", "07041987", "07031989", "07021991", "06061981", "06021986", "05121990", "05061988", "05031987", "04071988", "04071986", "04041986", "03101991", "03091983", "03051988", "03041983", "03031992", "02081970", "02061971", "02051970", "02041972", "02031974", "02021978", "02011977", "01121990", "01091992", "01081992", "01081985", "01011972", "vipergts", "vfntvfnbrf", "supernova", "stephen1", "sparkles", "snowbird", "singapor", "scissors", "pressure", "playball", "pizzaman", "pinetree", "pathfind", "papamama", "nightmar", "Mustang1", "montrose", "montecar", "masterbating", "maserati", "lockdown", "liverpool1", "kingking", "killer123", "jeepster", "ilovegod", "hellsing", "frederik", "feelgood", "escalade", "eleonora", "dominiqu", "delldell", "daughter", "contract", "conquest", "building", "buffalo1", "blacklab", "babycake", "7777777a", "31121986", "31121985", "31051991", "31051987", "30121988", "30121985", "30101988", "30061988", "29041988", "27091991", "26121989", "26061989", "26031991", "25111991", "25031984", "25021986", "24121989", "24121988", "24101990", "24101984", "24071992", "24051989", "24041986", "23091991", "23061987", "23041988", "23021992", "23021983", "22111988", "22091990", "22091984", "22051988", "21111986", "21101988", "21101987", "21091989", "21051990", "21021989", "20101987", "20071984", "20051983", "20031990", "20031985", "20011983", "1passwor", "19111985", "19081987", "19051983", "19041985", "18121990", "18121985", "18121812", "18091987", "17121985", "17111987", "17071987", "17071986", "17061987", "17041986", "17041985", "16121991", "16101986", "16041988", "16041985", "16031986", "16021988", "16011986", "15121983", "15101991", "15061984", "15011988", "14091987", "14061988", "14051983", "13101992", "13101988", "13101982", "13071989", "13071985", "13061991", "13051990", "13031989", "1234567890-", "12101989", "12071984", "12061987", "12041991", "12031990", "12021984", "11091986", "11091985", "11081986", "10101988", "10101980", "10091986", "10091985", "10081987", "10051988", "10021987", "10021986", "09041985", "09031987", "08041985", "08031987", "07061988", "07041989", "07021980", "06011982", "05121988", "05061989", "05051986", "04031991", "03071985", "03061986", "03061985", "03031987", "03031984", "03011991", "02111987", "02061990", "02011971", "01091988", "01071990", "01061983", "01051980", "01022010", "volleyba", "virginie", "treefrog", "therock1", "tennesse", "success1", "stockton", "skinhead", "qwqwqwqw", "playmate", "piercing", "password9", "painting", "nineball", "mohammad", "matchbox", "lfitymrf", "laetitia", "jellybean", "goldeneye", "erection", "entrance", "elisabet", "elements", "eclipse1", "eatmenow", "clemente", "charlie2", "cassandra", "cashmoney", "bobmarley", "baracuda", "alcatraz", "31051982", "30051988", "30051986", "29111988", "29051992", "29041989", "29031990", "28121989", "28071985", "28021983", "27111990", "27071988", "26071984", "26061991", "26021992", "26011990", "26011986", "25091991", "25091989", "25081989", "25071987", "25071985", "25071983", "25051988", "25051980", "25041987", "25021985", "24101991", "24101988", "24071990", "24061985", "24041985", "24041984", "23111986", "23101987", "23041991", "23031983", "22071992", "22071988", "21121989", "21111989", "21111983", "21101983", "21041991", "21041987", "21031986", "21021990", "21021988", "20081990", "20061991", "20061987", "20032003", "20031992", "1qw23er4", "1q1q1q1q", "19121988", "19081986", "19071989", "19041986", "18111983", "18071990", "18071989", "18071986", "18031986", "17121987", "17091985", "17071990", "17051983", "16091990", "15081989", "15071990", "15051992", "15051989", "15031991", "15011990", "14031986", "13091988", "13091987", "13091986", "13081986", "13071982", "13051986", "13041989", "13021991", "1234rewq", "12111984", "12091986", "12081993", "12071992", "12021990", "11111991", "11091990", "11061987", "11061986", "11061984", "11041985", "11031986", "10041984", "10031980", "10011980", "09051984", "08071985", "07081984", "07041988", "06101989", "06061988", "06041984", "05091987", "05081992", "05081986", "05071985", "05041985", "04111991", "04071987", "04021990", "03091988", "03061988", "03041989", "03041984", "03031991", "02091978", "01071988", "01061992", "01041993", "01041983", "01031981", "weare138", "vanessa1", "usmarine", "sniffing", "rfhfylfi", "rachelle", "qwerasdfzxcv", "patches1", "password99", "muhammad", "morrowind", "mallrats", "macintos", "macaroni", "lunchbox", "kcchiefs", "istheman", "implants", "ghjcnbnenrf", "gabriele", "forever1", "Fktrcfylh", "experienced", "dragonballz", "chouchou", "cheerleaers", "charisma", "celebrity", "cardinals", "captain1", "bubbles1", "billbill", "beatles1", "barefeet", "ballsack", "backbone", "asasasas", "apollo11", "abracadabra", "31101991", "31081989", "31051986", "31011985", "30101987", "30071992", "30061989", "30061985", "29121988", "29121984", "29111987", "29081987", "29081982", "29071986", "29051987", "29041987", "29031982", "28071984", "28061985", "28051988", "28041988", "28021989", "27101989", "27101987", "27091983", "27061990", "27051991", "26121987", "26111984", "26051990", "26041988", "26041983", "25091992", "25081987", "25051989", "24041990", "23091982", "23071986", "23061985", "23051984", "23021991", "22446688", "22091987", "22091985", "22061991", "22051990", "22041991", "21121988", "21091990", "21071990", "21071985", "21041990", "21021986", "20101986", "20072007", "20061980", "20051986", "20021991", "20011987", "19071983", "19021985", "19011985", "18061987", "18061986", "18011984", "17121986", "17111988", "17031992", "17021986", "16111989", "16061990", "16011991", "16011985", "15121985", "15111986", "15031987", "14101991", "14101983", "14051987", "14041991", "14021991", "13081987", "13071991", "13061990", "13031991", "12121984", "12101986", "12091990", "12081986", "12041987", "1111qqqq", "11061988", "11051989", "11041987", "11041986", "11021990", "10101991", "10081991", "10021983", "09101985", "09051990", "09011990", "08111983", "08071986", "08061986", "08031988", "08021989", "07021987", "06091989", "06081988", "06081986", "06071984", "06061990", "06051987", "06031986", "06021989", "05101984", "05061983", "05041986", "04081985", "04061990", "04061988", "04051987", "04021985", "04011990", "03121986", "03101985", "03061984", "02081975", "02031970", "02021977", "01051987", "01041989", "01031980", "01010101", "zoomzoom", "zerozero", "stiletto", "starwars1", "sexybitch", "sephiroth", "riffraff", "redheads", "poophead", "pertinant", "paulpaul", "nemrac58", "myXworld", "malaysia", "left4dead", "jesus123", "interest", "innocent", "hillbill", "hallowee", "goldeney", "generals", "gallaries", "fussball", "flyers88", "fabulous", "culinary", "constant", "citation", "cartman1", "cambridg", "bettyboo", "annaanna", "alterego", "alpha123", "77347734", "55BGates", "31031990", "30091985", "30081989", "30011992", "29081988", "29061984", "29041986", "29041984", "29011990", "29011988", "28121990", "28071988", "28051989", "28041983", "28011989", "27091987", "27091984", "27071983", "27061989", "27051986", "27011990", "26081983", "26041990", "25121986", "25111988", "25081983", "25021984", "25021983", "24081990", "24061984", "24021985", "23061988", "23041992", "23031989", "23021984", "22081987", "22031987", "21121987", "21091987", "21081990", "21061989", "21041986", "21011990", "21011985", "20111987", "20061992", "20051984", "20021990", "19631963", "19091986", "19011986", "18101989", "18091984", "18011991", "17081990", "17061992", "17021992", "16051986", "16041986", "16021989", "15081980", "15051991", "15031989", "15031986", "15021991", "15011991", "14785236", "14111987", "14091989", "14091988", "14051986", "14031990", "13121989", "13091990", "13061989", "13021984", "123456789987654321", "12071982", "12061980", "12031986", "12021987", "11121990", "11021988", "11021987", "11021984", "1020304050", "10111989", "10101987", "10071983", "10051989", "10051986", "10041989", "10021988", "10011989", "09061990", "09041990", "09011987", "08081983", "08081979", "08031992", "08021985", "08011988", "07111987", "07061986", "07041985", "07031986", "07021989", "06111990", "06111986", "06081990", "06071990", "06071986", "06051983", "05081989", "05081987", "05071986", "05071983", "05051993", "05051982", "05041991", "05041990", "05041983", "04121985", "04111989", "04031982", "04021987", "03111986", "03071984", "03051985", "03021987", "03011986", "02101975", "02061973", "02021992", "02011978", "01092010", "01091986", "01041986", "01031991", "z1x2c3v4b5", "vincent1", "thebeast", "tampabay", "tamerlan", "surprise", "sunshine1", "smartass", "rustydog", "rhfcfdbwf", "revoluti", "reloaded", "powerful", "pitchers", "Penthous", "passmast", "notredam", "nopassword", "nevermin", "natedogg", "mustang2", "mallorca", "loverman", "lenochka", "lebowski", "lavalamp", "JENNIFER", "interacial", "iiiiiiii", "houston1", "hardwood", "gogators", "francine", "fishtank", "edmonton", "duckduck", "dreaming", "doughnut", "dickdick", "darthvad", "dangerous", "crescent", "copenhag", "cleveland", "civilwar", "cashflow", "care1839", "capitals", "cantona7", "biohazard", "bigtruck", "bellagio", "auckland", "anonymous", "acapulco", "Aa123456", "741258963", "69camaro", "31071986", "30071983", "30041988", "29101992", "29091990", "29071988", "29041990", "29031983", "28121988", "28121987", "28121986", "28081985", "28061984", "28041991", "28041986", "28031990", "28021984", "27121988", "27051984", "27041987", "27021986", "27011985", "27011983", "26121985", "26121984", "26091985", "26021990", "26011989", "25091984", "25041984", "25041983", "24121990", "24121984", "24101987", "24011989", "24011986", "23071988", "23021987", "23011992", "22101988", "22091983", "22081990", "22081985", "21071986", "21071983", "21061987", "21051989", "21051983", "21011986", "20121985", "20111984", "20071985", "20011985", "19101989", "19101982", "19081991", "19031990", "18081989", "18051982", "18041988", "18041983", "17111989", "17111982", "17101991", "17091991", "17051993", "17051991", "17011986", "17011985", "16081985", "16071986", "16061984", "16021982", "15121989", "15111987", "15111985", "15101983", "15081984", "15041983", "15031984", "14101989", "14081986", "14061985", "14031985", "13121990", "13111986", "13111985", "13101990", "13101985", "13081988", "13081982", "13071992", "13051991", "13051988", "13041991", "13031992", "13031990", "13021992", "12345677", "123456123456", "12061990", "12061984", "112233445566", "11101990", "11081985", "11081984", "11081983", "11031991", "11031990", "11031987", "10121991", "10121989", "10111983", "10071991", "09051983", "09031991", "08091988", "08081985", "08031991", "07031988", "07031985", "07011989", "06111984", "06071988", "06071985", "06031988", "06031984", "05121985", "05121983", "05101986", "05061987", "05051988", "05051980", "05021989", "04121987", "04121986", "04051990", "03101983", "03081984", "03021982", "02101982", "02101974", "02091979", "02091974", "02071991", "02071974", "02021974", "01111990", "01091984", "01071989", "01061985", "01041981", "01041979", "01011950", "waterman", "waterfal", "trueblue", "trinity1", "trinitron", "tortoise", "topolino", "ticklish", "sweetheart", "supersonic", "stanley1", "skipper1", "shitshit", "seductive", "screwyou", "riversid", "riverrat", "redlight", "Qwerty123", "qweasdzx", "powerman", "parlament", "outsider", "nightwin", "natalie1", "monkeyboy", "messenger", "memememe", "marauder", "makeitso", "madagaskar", "ljxtymrf", "kikimora", "kamikadze", "jupiter1", "integral", "happines", "greywolf", "godbless", "gizmodo1", "foreplay", "fisherman", "favorite", "eighteen", "downhill", "dimadima", "dilbert1", "deerhunt", "cyclones", "coolhand", "converse", "computer1", "Christin", "chewbacc", "blueberr", "bendover", "asdfqwer", "animated", "aircraft", "789632145", "56565656", "32323232", "31121992", "31081985", "31071985", "31051990", "31011983", "30071990", "30061986", "29091986", "29071990", "29011983", "28101988", "28091984", "28081984", "28071989", "28061990", "28051981", "28031984", "27121986", "27081989", "26111987", "26051987", "25121982", "25091988", "25071989", "25071986", "25051992", "25051990", "25011991", "25011988", "24121985", "24081987", "24071989", "24061990", "23111990", "23081986", "23061983", "23031988", "23021990", "23011989", "23011988", "23011984", "22111991", "22031990", "22021984", "22011991", "21121984", "21031991", "21011992", "20091984", "20071990", "20071981", "20061989", "20051992", "20041981", "19601960", "19121986", "19121985", "19101983", "19071985", "18011990", "18011989", "17121990", "17081992", "17081988", "17071991", "17071984", "17041990", "17031991", "17021988", "16111987", "16031987", "16021983", "16011990", "15101987", "15081985", "15021988", "15011992", "14121986", "14111989", "14091982", "14071983", "14061982", "14021988", "1357908642", "13121984", "13081990", "13081984", "13021989", "123456789r", "12091987", "12071985", "12071983", "12051993", "12041985", "11111983", "11111979", "11091983", "11081992", "11071984", "11041988", "10121979", "10111988", "10111981", "10091989", "10091988", "10081988", "10041982", "10021985", "09121983", "09011991", "08061989", "08041988", "07081989", "07071986", "07071980", "07041986", "07021990", "06101991", "06081985", "06071987", "06031989", "05101983", "05071991", "05071990", "05011990", "04111986", "04081989", "04051983", "04041984", "04011988", "04011987", "03101989", "03101988", "03091991", "03081990", "03081988", "03071989", "03061989", "03051993", "03041990", "03031989", "03021989", "03011984", "02111989", "02081990", "02081972", "02081971", "02061992", "02061975", "01081980", "01071985", "01061984", "01051983", "01021986", "01021980", "wonderfu", "websolutions", "websol76", "vincenzo", "timoxa94", "stoppedby", "sprocket", "softtail", "soccer11", "sasha123", "rfhfvtkmrf", "q1q2q3q4q5", "popcorn1", "nokia5800", "myspace1", "markmark", "manunited", "magic123", "love1234", "lilwayne", "laserjet", "huskers1", "humphrey", "homepage", "griffith", "greenman", "greedisgood", "gogogogo", "giovanna", "gateway2", "gangbanged", "fuckme69", "freestyle", "foreskin", "fishcake", "fidelity", "dtkjcbgtl", "dipstick", "deadspin", "davedave", "daredevi", "continue", "bukowski", "blackbird", "blackberry", "bismarck", "beckham7", "baltimor", "babybear", "asdfg123", "a1a2a3a4", "99762000", "918273645", "31101989", "31051988", "30061982", "29121985", "29091991", "29081983", "29071987", "29061987", "28111987", "28111986", "28091992", "28091985", "28061983", "27101990", "27071984", "27051989", "27041989", "27041988", "27031985", "26091991", "26091984", "26081985", "26071990", "26041984", "26021985", "26011981", "25121989", "25091985", "25051984", "24101985", "24071988", "24071986", "24051987", "24051986", "24041992", "24041991", "24021987", "24021986", "23101988", "23081984", "23041990", "23031985", "23021993", "22111989", "22101991", "22041993", "22041990", "21091988", "21091986", "21091984", "21051985", "20spanks", "20091983", "20031984", "20011991", "20011984", "1z2x3c4v5b", "1q2q3q4q", "19101993", "19081985", "19061986", "19061984", "19041992", "19041987", "19031980", "19021982", "18081986", "18071988", "18051985", "18031981", "18021993", "17101990", "17091984", "17021990", "17021982", "16121985", "16121982", "16111983", "16091991", "16061992", "16031985", "15111991", "15111990", "15101992", "15091990", "15091983", "15071984", "15041985", "15031985", "14121987", "14101985", "14091991", "14081991", "14081989", "14031984", "13121988", "13071983", "13061984", "13061983", "13051989", "13051985", "13011985", "13011981", "123456987", "12101987", "12051992", "12041983", "12031989", "12021986", "12011988", "11101987", "11101985", "11081982", "11071983", "11041983", "11031984", "11031982", "11021991", "11011980", "10111987", "10101993", "10051985", "10051983", "10031986", "10031985", "09101986", "09071990", "09071984", "09061989", "09051985", "09011985", "08061990", "08041989", "07101985", "07091985", "07031991", "07021986", "07011988", "06101986", "06061989", "06061982", "06051989", "06031985", "06011987", "05051992", "05051983", "05031988", "05031986", "04121988", "04121984", "04071983", "04051984", "04041995", "04041989", "04031990", "03091986", "03031983", "02061970", "02051974", "01111987", "01081988", "01071980", "01031987", "01011961", "000000000", "zxcvb123", "wachtwoord", "vvvvvvvv", "volleyball", "valleywa", "trumpet1", "trooper1", "thinking", "Sunshine", "suckcock", "sopranos", "sarasara", "rosewood", "rfrfrfrf", "randolph", "qwerty13", "qweasdzxc123", "prophecy", "princess1", "pimpdaddy", "paperino", "nightowl", "negative", "naughty1", "mustang5", "montana1", "mazda323", "mastermind", "jurassic", "jefferson", "italiano", "heavenly", "halloween", "graduate", "gigabyte", "fivestar", "england1", "eldiablo", "creepers", "CORVETTE", "commander", "climbing", "ciaociao", "chickenwing101", "buddydog", "bradley1", "bisexual", "Benjamin", "abdullah", "31101986", "30101990", "30101984", "30051984", "30041992", "30031989", "30011983", "29101991", "29101985", "29011992", "28111984", "28091990", "28091987", "28091982", "28051983", "28031986", "28021981", "27071991", "27071982", "27041993", "27031983", "27011986", "26121990", "26121983", "26101989", "26101984", "26091989", "26091988", "26031992", "26011993", "26011987", "25101990", "25101986", "25091986", "25031988", "25021987", "25021978", "24101980", "24051985", "24021990", "23111985", "23111982", "23091988", "23091983", "23081990", "22111982", "22101985", "22051980", "22041983", "22011989", "21121980", "21041989", "21021984", "21021983", "21011987", "20081987", "20062006", "20061981", "20021981", "1million", "19611961", "19091992", "19081988", "19061989", "19041988", "18111989", "18111984", "18091991", "18081987", "18061988", "18041985", "18031993", "18021982", "17111986", "17081984", "17011701", "16121989", "16101985", "16091986", "16081988", "16071983", "16041993", "16041990", "16041984", "16031991", "15081987", "15071989", "15061983", "15041993", "15041989", "15041982", "15021989", "14121988", "14111988", "14061984", "14041989", "13121986", "13111988", "13071988", "13051983", "13031985", "13011984", "13011983", "123456789v", "123456789o", "1234567890z", "12111987", "12041994", "12041984", "12021980", "11121984", "11111982", "11021993", "11011985", "11011982", "10121984", "10101983", "10091991", "10051993", "10051984", "09121987", "09071987", "09071986", "09051988", "09041988", "08101989", "08061988", "08031983", "07121987", "07081982", "07061990", "07051989", "07051988", "06121988", "06111985", "06091987", "06051990", "06041989", "05121986", "05071989", "05061985", "05041984", "05021991", "05021985", "05011988", "04121982", "04091991", "04091987", "04081986", "04021988", "03101984", "03091984", "03081992", "03071983", "03061992", "03051989", "02121990", "02121983", "02041970", "02031993", "02011974", "01101985", "01081991", "01071983", "01041982", "01031990", "01021991", "zxcvzxcv", "Williams", "whoknows", "wdtnjxtr", "underwear", "unbelievable", "topsecret", "surveyor", "squerting", "smithers", "sealteam", "ronaldinho", "quant4307s", "prototype", "protocol", "princesa", "pizzahut", "ntktdbpjh", "nokia123", "nicetits", "mississi", "merchant", "mamochka", "lucky123", "libertad", "justice1", "instinct", "infected", "ilya1234", "housewifes", "highlife", "hartford", "happyman", "goodyear", "godspeed", "flvbybcnhfnjh", "flanders", "fighting", "dtxyjcnm", "daredevil", "bismilla", "bigbucks", "baberuth", "asdasd123", "alessand", "access99", "8888888888", "3rJs1la7qE", "34343434", "31121983", "31031986", "30111986", "30101986", "30081990", "30071985", "30031987", "30011980", "29121986", "29111983", "29091985", "29091982", "29051988", "29051986", "29051984", "29031989", "29031986", "29021988", "28111990", "28071983", "28051992", "28041989", "28031991", "28031988", "28031983", "27101992", "27071990", "27071985", "27061984", "27021987", "26111989", "26061983", "26031985", "26021989", "26011988", "25121990", "25111989", "25111986", "25041989", "25041980", "25031992", "25031986", "25021990", "25021989", "25011987", "24681012", "24121982", "24111983", "24091990", "24081986", "24061989", "24021989", "23071984", "23061980", "23051988", "23041985", "23011991", "23011982", "22121982", "22111990", "22101987", "22101981", "22041989", "21121992", "21061990", "21051987", "21051984", "20121987", "20111985", "20051981", "20041992", "20041984", "20031980", "20021983", "20011981", "19121987", "19081983", "19021988", "18101990", "18101988", "18081990", "18071983", "18021991", "17121983", "17101992", "17091986", "17051986", "17031988", "17031984", "17031983", "17021983", "16111986", "16101989", "16081991", "16071988", "16071985", "16061989", "15121990", "15121986", "15101984", "15071992", "15061987", "15051982", "15031992", "15021987", "15011981", "14111990", "14091986", "14081982", "14061990", "14041984", "14031987", "14011991", "13071993", "13051992", "13041984", "13031980", "13011993", "123581321", "123456as", "123321123321", "12121981", "12121977", "12051981", "12041989", "12011991", "11111989", "11111988", "11091987", "11071990", "11051991", "11031992", "11021992", "11021981", "10121982", "10101992", "10101982", "10071984", "10041985", "09121985", "09121982", "09071988", "09061991", "09051981", "09031990", "08101987", "08101980", "08061992", "08061985", "08021991", "07101989", "07091987", "07081992", "07061985", "07041990", "07041983", "07021984", "06101987", "06101985", "06091991", "06061983", "06051985", "06021988", "05111992", "05091985", "05081985", "05031989", "04111992", "04061982", "04051989", "03121985", "03091987", "03081987", "03071992", "03071990", "03051984", "02091972", "02081978", "02041991", "02041990", "02031995", "02031976", "02021993", "02021975", "01121985", "01121984", "01101990", "01091980", "01091979", "01081986", "01071991", "01061979", "vodafone", "valeriya", "tickling", "SUPERMAN", "starlight", "splendid", "special1", "sokolova", "skydiver", "shredder", "saxophon", "salvatore", "rockrock", "pounding", "playboy2", "petrovich", "nancy123", "molly123", "maxpower", "marcella", "locoloco", "livewire", "lionheart", "joystick", "jennifer1", "infamous", "hugoboss", "hospital", "Groupd2013", "gianluca", "ghbdtnrfrltkf", "ghbdtndctv", "fujifilm", "frankie1", "flathead", "fisherma", "feathers", "favorite2", "fantasies", "experience", "envelope", "dragonfly", "cornhole", "close-up", "Charlie1", "chadwick", "blueberry", "blackhawk", "bigblack", "beethove", "anthony7", "andyandy", "alexander1", "aaaaaaaaa", "a1b2c3d4e5", "987654321a", "85208520", "74123698", "31101988", "31071983", "31011989", "30121984", "30111990", "30111989", "30071987", "30061981", "30051992", "29091980", "29081986", "29041992", "29031991", "27101986", "27081985", "27071989", "27071986", "27051992", "27051985", "27031990", "26111986", "26021988", "25121983", "25111992", "25031993", "24051979", "24031985", "24021983", "24011992", "24011991", "24011983", "23121983", "23101990", "23091994", "23081991", "23081988", "23041989", "23031991", "23031980", "23011980", "22121985", "22101989", "22101983", "22031989", "22021992", "22021987", "22011993", "22011987", "21111992", "21091985", "21071994", "21071982", "21061983", "21031981", "20121990", "20121982", "20081988", "20081985", "20081984", "20042004", "20031983", "20021992", "20021989", "20021987", "20021980", "1qaz2wsx3edc4rfv", "19121982", "19111984", "19081992", "19081990", "19021987", "19021986", "18121992", "18111988", "18071981", "18061992", "18061984", "18051992", "18051986", "18041987", "17081989", "17061985", "17061983", "17051992", "17041984", "17031985", "17021991", "17011991", "16111984", "16101992", "16081989", "16061983", "16041987", "16011983", "159753456", "15081983", "15071991", "15061990", "15051983", "15041990", "15041986", "14111984", "14111982", "14061983", "14051993", "14051985", "14021992", "14021984", "13121987", "13091985", "13081991", "13011986", "12121980", "12091983", "12081989", "12041978", "12031991", "12031984", "11121989", "11121981", "11091988", "11051985", "11051982", "11051979", "11041993", "11031989", "10121990", "10031992", "10031984", "10011987", "09101988", "09091991", "09091987", "09071991", "09061986", "08121989", "08091989", "08081992", "08071983", "08061984", "08021988", "08011987", "07081983", "07051992", "06121982", "06071989", "06051988", "06041990", "06021984", "06021983", "06011991", "06011986", "05121989", "05111982", "05031984", "05021993", "04111987", "04101988", "04091985", "03091990", "03051981", "03051979", "03041988", "03041985", "03031994", "03021990", "03011990", "03011985", "02121988", "02121986", "02121981", "02091990", "02041971", "02031972", "02031971", "02022009", "01121989", "01101986", "01081984", "01061989", "01041991", "01041984", "yaroslav", "vampire1", "treetree", "tonytony", "smirnova", "slapnuts", "sandberg", "roosters", "rfgbnjirf", "producer", "PRINCESS", "pictuers", "pennywis", "nosferatu", "nathanie", "musician", "monkey69", "mercury1", "mainland", "Madala11", "ludacris", "lovehate", "lockerroom", "letsfuck", "landmark", "jojojojo", "jennings", "hydrogen", "horsemen", "goofball", "georgina", "garrison", "francisco", "ejaculation", "dragon123", "dominique", "dirtydog", "devilman", "daydream", "crazyman", "catfight", "carpediem", "buster12", "browndog", "blackops", "blackice", "beverley", "basement", "bajingan", "badabing", "atreides", "architec", "advanced", "abc123456", "a1s2d3f4g5", "31121982", "31071988", "30111982", "30101985", "30091987", "30081986", "30071991", "30071982", "29111985", "29071993", "29051991", "29011991", "29011980", "28111982", "28101991", "28091988", "28041990", "28021988", "28011991", "27121990", "27121981", "27111992", "27111984", "27081988", "27031984", "27021985", "26071985", "26061990", "26041987", "25111985", "25081994", "25071984", "25051986", "25051983", "24111988", "24111985", "24111982", "24091988", "24091984", "24081985", "24051991", "24041987", "24031989", "24031981", "24031980", "24021984", "24011988", "24011984", "23051989", "23041984", "23041983", "22061982", "22051985", "22021994", "22011990", "21121991", "21101980", "21091991", "21081991", "21081988", "21081986", "21061991", "21041988", "21041983", "21031992", "20101984", "20101982", "20091985", "20021993", "1Michael", "19621962", "19091987", "19091980", "19071991", "19041993", "19041989", "18121988", "18111985", "18071991", "18051984", "18041984", "17091981", "17081987", "17061982", "17041988", "17031986", "16091992", "16081980", "16061981", "16041992", "16041989", "16031992", "16011988", "15121984", "15101985", "15061993", "15051993", "15021984", "14071989", "14061986", "14031991", "13111989", "13101986", "13091982", "13081983", "13041986", "12349876", "12345687", "123456789123456789", "12091989", "12091985", "12061989", "12061985", "12051983", "12041982", "12011992", "11081991", "11081980", "11061992", "11061980", "11041992", "11001001", "10241024", "10081981", "10011985", "0o9i8u7y", "09111988", "09111983", "09101984", "09091985", "09081986", "09081984", "09031992", "09021987", "08111987", "08081984", "08051983", "08041992", "08041990", "08031989", "08031980", "07121984", "07111982", "07101983", "07081985", "07071994", "07061991", "07051986", "07011980", "06081991", "06081983", "06031987", "06011984", "05071987", "05031992", "05031981", "05011989", "04101992", "04081992", "04081982", "04081978", "04071985", "04051986", "04041992", "04041982", "04031984", "04011986", "03081985", "03071980", "03061991", "03061990", "03021992", "03011992", "02121985", "02101972", "02101970", "02051971", "02041992", "02031992", "02022010", "02021972", "01121980", "01091990", "01051992", "01011996", "zxcvasdf", "wrinkles", "warcraft3", "violator", "thumbnils", "tangerin", "tailgate", "stonewal", "spiderman1", "sometime", "sleeping", "skeleton", "sickness", "sexymama", "scorpions", "satellite", "qwedsazxc", "popopopo", "passcode", "offspring", "nothing1", "nokia5530", "Nicholas", "motocross", "monterey", "minnesot", "mike1234", "melanie1", "mannheim", "livelife", "lionhear", "lighthou", "lapochka", "knickerless", "jupiter2", "jesus777", "jediknig", "japanees", "hillside", "guillerm", "graywolf", "gfgfvfvf", "forester", "firestorm", "finalfantasy", "fernande", "euphoria", "escorpio", "earthlin", "deathnote", "contortionist", "bluestar", "bionicle", "billabong", "bernardo", "adelaide", "aaaa1111", "963258741", "911turbo", "42424242", "31101985", "31071989", "31071984", "31011992", "30091988", "30091983", "30011993", "2wsx3edc", "29101990", "29071982", "29061982", "29031987", "28111989", "28101985", "28091993", "28091986", "28071993", "28071982", "28061989", "28031989", "27121989", "27111986", "27111982", "27081987", "27051988", "27041983", "27011982", "26121986", "26111978", "26101988", "26101983", "26041989", "26031982", "26021986", "26011985", "25111990", "25091983", "25071992", "25061984", "25051991", "25041992", "25021994", "25011983", "24111992", "24111991", "24051988", "24041989", "23121984", "23101981", "23091984", "23071992", "23071981", "23021982", "22111986", "21081980", "21061980", "21051979", "21021992", "21021991", "20121984", "20111989", "20081989", "20071983", "20061985", "20041987", "20041980", "20031989", "20021982", "20011986", "19121978", "19051990", "19051989", "19011990", "19011988", "19011981", "18121986", "18081982", "18061993", "18061982", "18051991", "18041989", "18031989", "17111979", "17101988", "17101985", "17051985", "17031989", "17011992", "16101984", "16071989", "16051991", "16021991", "16021986", "16011982", "15121993", "15071981", "15071980", "15041984", "15011984", "14121991", "14121984", "14121979", "14111991", "14101992", "14091984", "14081992", "14081987", "14071985", "14011990", "13101989", "13091989", "13041990", "13041985", "13031988", "13031983", "13021986", "13011991", "13011990", "123qwe123qwe", "12345123", "12091982", "12051982", "12041977", "12031982", "12021989", "12021983", "12011986", "11121983", "11121980", "11111984", "11101988", "11101982", "11071991", "11061983", "11041980", "11031985", "11031980", "11011988", "10121988", "10111985", "10081993", "10081986", "10081982", "10071980", "10061991", "10061990", "0987654321q", "09121989", "09111985", "09091989", "09081990", "09071985", "09031989", "09031986", "09031981", "09021990", "09021986", "08121983", "08111986", "08071990", "08041982", "08041980", "08031993", "08021992", "07121992", "07111986", "07091984", "07091983", "07081990", "07081981", "07071992", "07051985", "07041984", "06021981", "05111991", "05111989", "05111984", "05061984", "05061981", "05061980", "05041989", "05041988", "04101984", "04101980", "04091990", "04081983", "04061985", "04031989", "03121990", "03051991", "03031982", "03021993", "02111990", "02111985", "02081991", "02071973", "02011972", "01111989", "01111984", "01101989", "01061982", "01031982", "01021994", "01021984", "woodwork", "winter99", "wednesda", "waterski", "vfpfafrf", "vflfufcrfh", "vfhbyjxrf", "uuuuuuuu", "troubles", "transexual", "thumper1", "thetruth", "SUNSHINE", "spamspam", "sephirot", "scirocco", "sarajevo", "rushmore", "rodrigue", "revival47", "qazqazqaz", "qaz123wsx", "qawsedrftg", "priyanka", "pornographic", "pippen33", "paladin1", "nineteen", "newproject2004", "myfriend", "motdepasse", "maurizio", "masturbation", "letmesee", "leonidas", "lamborghini", "komputer", "kickflip", "justinbieber", "internal", "insecure", "india123", "Iloveyou", "ilovepussy", "hugetits", "honeybun", "helsinki", "fuzzball", "fullback", "freewill", "fhvfutljy", "dominick", "disaster", "dfcbkbcf", "Danielle", "daniella", "cowboyup", "comicbookdb", "chowchow", "checkmat", "carlisle", "calendar", "businessbabe", "bulletin", "batman12", "basketbal", "BaBeMaGn", "attorney", "assmunch", "as123456", "angel666", "allstate", "allison1", "31081987", "31031985", "30111988", "30091986", "30081982", "30061992", "30061980", "30061979", "30051981", "30011988", "29121989", "29121982", "29101986", "29101982", "29091988", "29041982", "29011993", "29011989", "28071991", "28051991", "28051984", "28031985", "28021991", "28011984", "27731828", "27101985", "27051990", "27031988", "27021984", "26111992", "26081989", "26081988", "26071983", "26071982", "26051993", "25101991", "25101987", "25101985", "25061992", "25061988", "25041990", "25031980", "25011989", "25011982", "24091989", "24091987", "24091985", "24081982", "24031984", "24031983", "24021993", "23121990", "23121989", "23121982", "23101986", "23101985", "23091992", "23081985", "23041993", "23041982", "23011987", "22121988", "22121984", "22121978", "22111987", "22101990", "22091981", "22071981", "22011982", "21111984", "21071988", "21071984", "21051993", "20091989", "20091987", "20051991", "20041983", "20011979", "19091984", "19081982", "19071984", "19061982", "19051988", "19051985", "19051977", "19041990", "19021993", "19021984", "19011993", "18121979", "18101986", "18101983", "18091989", "18081992", "18071979", "18061989", "18061981", "18051993", "18031985", "18031982", "18031980", "18011993", "18011992", "17121993", "17121992", "17091983", "17081986", "17051981", "17031993", "17011989", "17011983", "16121990", "16121983", "16111992", "16081984", "16041978", "16021984", "15101982", "15081992", "15071982", "15061992", "15051988", "15041980", "15021993", "14121985", "14111985", "14101990", "14051991", "14051982", "14011983", "13121982", "13111982", "13101984", "13071979", "13061988", "13041983", "13011989", "12101983", "12081994", "12051980", "12041980", "12021993", "12021982", "12011993", "12011979", "11101984", "11041974", "11011986", "10111991", "10111990", "10101981", "10101975", "10091992", "10091980", "10081984", "10061988", "10041992", "10041979", "10021984", "10021982", "09101991", "09091990", "09071981", "09061988", "09061983", "08091987", "08091986", "08091985", "08081981", "08071984", "08071982", "08051992", "08041984", "08021984", "08011989", "07101988", "07101986", "07091989", "07051984", "07041980", "07021988", "07011985", "06091985", "06081989", "06071982", "06051991", "06021992", "06011989", "05121984", "05111983", "05101990", "05101989", "05081991", "05011985", "05011984", "04101989", "04101986", "04101977", "04071982", "04061980", "04011989", "03121987", "03111984", "03101979", "03081983", "03051990", "03031981", "03021984", "03021979", "02121992", "02101990", "02091991", "02071972", "02071970", "02051991", "02011973", "01101984", "01101979", "01081987", "01081982", "01071978", "01051993", "01051984", "01021995", "01011998", "yeahyeah", "winfield", "vivitron", "vfhnsirf", "ursitesux", "trousers", "ticktock", "survival", "smoke420", "ShitHead", "sfgiants", "schubert", "rdfhnbhf", "pussy4me", "password01", "nocturne", "newstart", "nathaniel", "monolith", "mojojojo", "metallica1", "maxpayne", "magdalena", "macgyver", "losangeles", "lolololo", "Liverpool", "lighthouse", "laughing", "lacrimosa", "kissmyas", "jeffrey1", "imtheman", "ibilltes", "honduras", "homebrew", "hawthorn", "gabrielle", "futyn007", "funtimes", "fruitbat", "frogfrog", "friday13", "frenchie", "forsberg", "fordtruc", "fishface", "evangeli", "embalmer", "elevator", "duracell", "dominika", "diplomat", "dima1995", "diamante", "dallas22", "costanza", "corvet07", "cornelia", "cobra427", "clueless", "chevys10", "capoeira", "bobobobo", "BIGDADDY", "athletic", "aerosmit", "adventure", "adrianna", "administrator", "addicted", "abcdefg1", "3edc4rfv", "31081990", "31071991", "31071982", "31071980", "31051977", "31031982", "30121990", "30101991", "30091992", "30081988", "30071989", "30071979", "30051991", "30041990", "30031985", "30031984", "30011989", "29121981", "29111982", "29101984", "29091984", "29071981", "29061991", "28111988", "28091989", "28081988", "28051980", "28031981", "28011985", "27121982", "27091988", "27041986", "27031993", "27031991", "27011987", "27011981", "26081987", "26051985", "26031980", "26011991", "25121988", "25121984", "25111982", "25111978", "25071978", "25051981", "25041986", "25031989", "24111981", "24081984", "24031991", "23121991", "23111988", "23101992", "23081992", "23071989", "23051980", "23041996", "23021977", "22121992", "22111983", "22081981", "22051984", "22051982", "22041992", "22041984", "22031981", "22011984", "21121978", "21111988", "21101984", "21101981", "21081989", "21061993", "21061992", "21041984", "21011984", "21011981", "20091990", "20081982", "20071993", "20061982", "20011992", "20011980", "1a2s3d4f5g", "19111988", "19101988", "19101985", "19101984", "19091985", "19081984", "19051981", "19021983", "19021980", "18181818", "18111990", "18101991", "18091983", "18041992", "18021989", "17121991", "17101980", "17071988", "17051979", "17041989", "17011984", "16091984", "16081990", "15101989", "15091986", "14121990", "14121983", "14111983", "14101984", "14081984", "14051992", "14051981", "14051977", "14041982", "13121980", "13111991", "13101993", "13101983", "13071994", "12locked", "1234KEKC", "1234567aA", "1213141516", "12121983", "12111981", "12091984", "12041993", "12011995", "11111978", "11101989", "11081978", "11041989", "10101984", "10061983", "10031983", "10021993", "10021990", "10011001", "09091984", "09061987", "09051991", "09051989", "09051975", "09041991", "09031985", "08121985", "08121984", "08121982", "08101985", "08091984", "08081982", "08061983", "08031990", "07121988", "07111985", "07101990", "07091986", "07011986", "06121989", "06121986", "06081992", "06081984", "06081979", "06041986", "05111985", "05091992", "05091991", "05081983", "05081981", "05081977", "05061982", "05051984", "05011992", "04101991", "04091989", "04071989", "04061993", "04031994", "04031985", "03101990", "03101986", "03081993", "03081991", "03061982", "03051982", "03051980", "03011989", "02101971", "02091993", "02091970", "02071990", "012345678", "01111988", "01101982", "01081978", "01071981", "01051979", "01042000", "01012006", "01011967", "00001111", "zxczxczxc", "zimbabwe", "woodstock", "wingzero", "wellingt", "truffles", "tiberian", "superbow", "stirling", "stephens", "Steelers", "start123", "sparhawk", "somebody", "silverado", "sammydog", "saltydog", "rfhlbyfk", "q1q2q3q4", "pregnant", "phantom1", "neworder", "needforspeed", "monkeyman", "lol12345", "lingerie", "landrove", "lambchop", "ladybird", "L58jkdjP!", "kristin1", "klopklop", "josephine", "jessica2", "Internet", "illmatic", "hunter12", "hondacbr", "greentea", "greatest", "glendale", "ghjdthrf", "Gandalf1", "friends1", "frederick", "firehawk", "fernanda", "fantasti", "dreamcast", "dragon01", "disturbed", "delphine", "deepthro", "daedalus", "chinchin", "chemistry", "casablanca", "buckwhea", "buckaroo", "bigpenis", "bertrand", "beachbum", "armageddon", "arizona1", "aligator", "alfarome", "Alexander", "890098890", "666666666", "31101983", "31081982", "31051989", "31051983", "30071988", "30061990", "30061984", "30041984", "30041983", "30031979", "29121992", "29101989", "29091989", "29091983", "29071980", "29041980", "29021984", "29011984", "28111985", "28101989", "28101979", "28061981", "28011986", "27111978", "27081984", "27021988", "27011989", "26121988", "26121981", "26111988", "26101985", "26101981", "26081990", "26051992", "26051989", "26031989", "26011992", "26011984", "25121991", "25091982", "25071981", "25071980", "25061983", "25061981", "25031985", "25031982", "25011984", "24101994", "24071982", "24051984", "24041983", "23121988", "23111991", "23111984", "23111983", "23081983", "23061991", "23061986", "23051981", "23031984", "23021978", "22334455", "22061992", "22041982", "21101990", "21101982", "21091982", "20111991", "20111990", "20101992", "20101990", "20101985", "20071987", "20021984", "20011990", "1a2a3a4a", "19121990", "19111990", "19061988", "19041983", "19041978", "19031986", "19021992", "19011982", "18121989", "18111992", "18111982", "18081985", "18061983", "18061980", "17121988", "17101989", "17091992", "17091982", "17091979", "17071992", "17071983", "17061993", "17051982", "17041983", "16121988", "16101991", "16071993", "16061991", "15101981", "15061994", "15061991", "15041981", "15031994", "15031983", "15011993", "15011982", "14101993", "14071984", "14061987", "14041993", "14041976", "14031980", "14031978", "14011984", "14011982", "13245768", "13081978", "13061981", "13041992", "13021995", "123mudar", "123456789l", "123456789123", "12345612", "12340987", "12111988", "12111986", "12111982", "12071980", "12051984", "12011984", "12011980", "11121991", "11101979", "11091992", "11091991", "11081993", "11051983", "11021983", "10111982", "10091983", "10061980", "10011982", "09121992", "09101982", "09091979", "09081989", "09061984", "09051978", "09041982", "09021991", "09021985", "08101984", "08091981", "08081991", "08071991", "08051986", "08051985", "08051984", "08031982", "08031977", "08021986", "07121985", "07071983", "07041979", "07031984", "07021985", "06121987", "06111982", "06061991", "06061984", "06041991", "06011990", "05111990", "05101987", "05051981", "05031983", "05021990", "04111990", "04111985", "04101990", "04071990", "03111992", "03091982", "03071991", "03071978", "03061983", "03021988", "03011988", "02081994", "02041993", "02021994", "02021970", "01121982", "01111983", "01101991", "01061991", "01031992", "01031976", "01021983", "01011966", "01011965", "ytngfhjkz", "yourmama", "wingchun", "wildlife", "welcome2", "wednesday", "undertow", "uncencored", "trailers", "temptress", "submarin", "sublime1", "starbucks", "spalding", "songbird", "snapshot", "shevchenko", "sevenof9", "seahorse", "santacru", "sandman1", "salesman", "rt6YTERE", "rktjgfnhf", "raymond1", "ramstein", "prudence", "prestige", "paramore", "papabear", "omegared", "nonmembe", "nastenka", "morticia", "morozova", "monkey123", "milkyway", "michelle1", "masterbaiting", "marajade", "longshot", "letmeinn", "kenneth1", "johnston", "ireland1", "hulkster", "housewife", "hellohel", "headache", "gorillaz", "goldrush", "girfriend", "Garfield", "fuckthat", "fourteen", "flipper1", "fireblade", "evildead", "everyday", "dropkick", "drifting", "dragrace", "doorknob", "domenico", "daniel12", "costaric", "contests", "bugsbunn", "bubblegum", "blondinka", "blackbelt", "benedict", "BaBeMaGnEt", "asslover", "anna2614", "78787878", "74227422", "74107410", "43046721", "31121991", "31101984", "31031989", "31031980", "30101983", "30101982", "30051980", "30051979", "30041982", "30031991", "30031983", "30011991", "29121990", "29101988", "29091977", "29061983", "29041993", "29011986", "28111983", "28101992", "28091991", "28091981", "28081989", "28071990", "28071978", "28061991", "28041980", "28011983", "27111991", "27111988", "27091990", "27091989", "27061980", "27051983", "27011984", "26111991", "26111982", "26091990", "26091987", "26071992", "26031983", "26011979", "25101983", "25101978", "25071991", "25051993", "25031994", "25021992", "25011994", "24101983", "24081992", "24071984", "24071983", "23101984", "23101982", "23071991", "23071990", "23071982", "23061984", "23061976", "23051978", "23031992", "23021981", "23021975", "23011983", "23011981", "22111979", "22091989", "22081992", "22081989", "22051981", "22041976", "22011983", "22011975", "21091980", "21061984", "21041994", "21041993", "21041978", "21031989", "20071992", "20071989", "20041989", "1password", "1a2b3c4d5e", "19111989", "19111981", "19091982", "19071994", "19051980", "19041981", "19041980", "19011991", "18121980", "18091988", "18071980", "17111984", "17031990", "17021981", "16161616", "16111988", "16111985", "16091985", "16081992", "16081983", "16071982", "16071980", "16041991", "16031993", "16021985", "15111981", "15101979", "15091981", "15061986", "15051980", "15041992", "15041991", "15031975", "15011989", "14121993", "14121980", "14071990", "14071980", "14051979", "14031982", "14021982", "14011992", "13111987", "13091980", "13081981", "13061982", "13041981", "13011992", "123698741", "123456789p", "12101979", "12091992", "12081992", "12081981", "12061994", "12061992", "12051991", "12031992", "12011990", "11121992", "11111992", "11101983", "11101980", "11071980", "11061993", "11031993", "11021994", "11021989", "10121992", "10121976", "10101977", "10091993", "10071993", "10061992", "10051992", "10041993", "10031981", "10021989", "10021981", "10011993", "10011991", "10011984", "09091982", "09081987", "09061981", "09041984", "09021982", "09011992", "09011989", "09011980", "08111991", "08111990", "08041981", "08011980", "07121983", "07081980", "07071993", "07071978", "07061984", "07041982", "07041981", "07011987", "07011982", "06121991", "06121985", "06111987", "06111983", "06091990", "06091988", "05101988", "05091984", "05061991", "05041987", "05021981", "05011983", "04121989", "04101985", "04091979", "04071992", "04071984", "04051982", "04021986", "04021984", "04021982", "03081980", "03081979", "03061977", "03041992", "03021978", "02121989", "02121980", "02111986", "01101980", "01061993", "01051974", "01031993", "01011968", "wapapapa", "victory1", "verygood", "vancouver", "toulouse", "tooltime", "tequiero", "sunderla", "starlite", "sooners1", "snowflake", "skeeter1", "singapore", "shinigami", "seventeen", "sanity72", "samadams", "restless", "redstorm", "rb26dett", "qwerty99", "pussyeat", "P@ssw0rd", "porsche911", "plumbing", "pennstat", "peaceful", "partners", "paranoia", "necklace", "motherfu", "milamber", "memories", "marybeth", "manifest", "mahalkita", "machines", "losangel", "littlema", "liberty1", "kfcnjxrf", "kazanova", "j3qq4h7h2v", "infinite", "ignatius", "horseman", "honeydew", "heinlein", "glennwei", "geibcnbr", "fuckshit", "fordf350", "fktyeirf", "fakepass", "everques", "enter123", "dortmund", "dominate", "discovery", "desperado", "demon666", "dagobert", "churchil", "christophe", "Christia", "chopper1", "chairman", "caldwell", "brisbane", "braveheart", "bonethug", "bluenose", "birthday4", "bettyboop", "avalanche", "austin316", "augustin", "allnight", "allblack", "alex1234", "alejandra", "aerosmith", "admin123", "31121984", "31101982", "31071977", "31051992", "30111983", "30111979", "30081983", "30041993", "30041989", "30041980", "29111984", "29081991", "29081989", "29071991", "29071989", "29061981", "29051993", "29041994", "29031993", "28121985", "28111991", "28081981", "28071981", "28031987", "28021987", "28021978", "28011992", "28011990", "27121991", "27111987", "27101991", "27091979", "27071994", "26121991", "26101990", "26091981", "26081992", "26081981", "26071991", "26071988", "26071979", "26061992", "26051983", "26041985", "26021991", "25121980", "25111980", "25081993", "25081984", "25071988", "25061990", "25031979", "25021991", "24121993", "24091982", "24081989", "24061991", "24051993", "24051992", "24031992", "24031982", "24011982", "23121987", "23121985", "23081980", "23051982", "23031982", "23011986", "22121990", "22101984", "22101978", "22091977", "22061981", "22051983", "22041981", "22041979", "22031983", "22021991", "21111987", "21111982", "21101985", "21051981", "21031983", "20101991", "20081993", "20081983", "20071982", "20031981", "20011982", "19571957", "19121992", "19101991", "19081978", "19071982", "19051993", "19051984", "18273645", "18111981", "18101984", "18091982", "18051980", "17121984", "17111992", "17091978", "17081985", "17081982", "17071980", "17061990", "17061984", "17051984", "17041992", "17021984", "16121992", "16101988", "16071992", "16051984", "16041983", "16031994", "16031983", "16021994", "15121992", "15121988", "15121982", "15121977", "15101990", "15101980", "15091992", "15031993", "15021978", "14091983", "14081983", "14061989", "14051988", "14051984", "14041985", "14021995", "14021977", "14011985", "13241324", "13121991", "13111980", "13081993", "13081980", "13021988", "12345asd", "12345678900", "12345654321", "12111983", "12091981", "12071981", "12031993", "11111990", "11111985", "11111980", "11101991", "11061981", "11041984", "11021982", "10101978", "10081992", "10081980", "10071982", "10021991", "10011978", "09101980", "09081982", "09071982", "09041989", "09021993", "09021984", "08121988", "08091982", "08081976", "08021980", "08011990", "08011983", "07121989", "07111984", "07071976", "07021993", "07021983", "06111989", "06091984", "06071991", "06061980", "06021985", "05101982", "05081979", "05071981", "05071977", "05021980", "04081991", "04081984", "04081981", "04061994", "04061989", "04051980", "04021981", "03081982", "03071982", "03041975", "03031985", "03021985", "03011983", "02061993", "01121979", "01111986", "01101988", "01091983", "01081983", "01071982", "01031978", "0000000000o", "zaq12345", "x72jHhu3Z", "William1", "watermelon", "utahjazz", "tonyhawk", "thething", "testibil", "terriers", "scandinavian", "rerfhtre", "rammstei", "qazxsw123", "penetrating", "peaceout", "pathfinder", "passthie", "partizan", "navigato", "mypasswo", "meandyou", "maximus1", "maurolarastefy", "mastermi", "master123", "marymary", "manhatta", "lasttime", "lancaster", "kokokoko", "ilikesex", "hornyman", "helphelp", "gymnastic", "gotyoass", "goodlife", "galeries", "fuckmehard", "freedom2", "frank123", "forgotten", "firestar", "everton1", "domainlock2005", "disabled", "dickweed", "detectiv", "cybersex", "cxfcnkbdfz", "crockett", "charming", "charlie123", "blessed1", "biscuits", "astonvil", "arcangel", "anakonda", "alkaline", "Alexandr", "555555555", "333333333", "31121980", "31101990", "31101978", "31081988", "31081983", "31031984", "31011986", "30121983", "30111985", "30101981", "30091994", "30091982", "30081987", "30061991", "30011978", "30011977", "29121991", "29091993", "29091981", "29071992", "29041983", "29031985", "29031984", "29021980", "28121983", "28121982", "28121981", "28081991", "28061982", "28051993", "28031979", "28011981", "27101983", "27051993", "27041984", "27021982", "26121977", "26101992", "26101982", "26061981", "26051984", "26021984", "26011983", "25081991", "25081980", "25061994", "25061991", "25061989", "25051995", "25051982", "25051979", "25041979", "25031990", "24121981", "24111984", "24091981", "24031986", "24021994", "24011981", "23101991", "23101979", "23091990", "23091978", "23081989", "23081987", "23081977", "23061979", "23051992", "23041977", "23021973", "22101992", "22091982", "22081977", "22071982", "22061986", "22051992", "22031985", "22031978", "22021982", "22021980", "21121983", "21121981", "21121977", "21111981", "21101992", "21101991", "21091983", "21081981", "21051982", "21031993", "21011983", "20112011", "20111982", "20101989", "20101983", "20071991", "20051990", "20051980", "20041991", "20031993", "19591959", "19121984", "19091993", "19091991", "19091978", "19071995", "19061983", "19031989", "19031982", "18121993", "18111979", "18101992", "18101982", "18081983", "18071987", "18021990", "18021981", "18011983", "17121980", "17111980", "17101979", "17081991", "17061979", "17031994", "17011988", "16101982", "16091980", "16081987", "16081979", "16061980", "16031989", "16031980", "16021993", "16011984", "15121979", "15101988", "15091978", "15061989", "15031980", "14091979", "14081993", "14041981", "14021980", "14011980", "13121979", "13101994", "13081992", "13071986", "13031984", "13011976", "12241224", "12121992", "12081991", "12071994", "12071986", "12071976", "12061991", "12041976", "12021992", "11122233", "11021980", "11011981", "11011977", "10121980", "10101979", "10061981", "09121990", "09121986", "09091980", "09011988", "09011984", "08121981", "08091992", "08071992", "08071979", "08061981", "08011984", "07111989", "07081991", "07081988", "07081978", "07061982", "07051993", "07051981", "07031987", "07011992", "07011983", "06121983", "06101988", "06101982", "06051992", "06041980", "06031990", "06021982", "06011985", "05121991", "05091986", "05051975", "05041992", "05041982", "05041981", "04111982", "04071977", "04061981", "04051991", "04051981", "04041993", "04041981", "04041979", "04021992", "04011992", "04011991", "04011985", "04011980", "03121983", "03121982", "03111989", "03101981", "03091985", "03091980", "03061979", "02111984", "02111983", "02111982", "02011992", "02011970", "01121975", "01111991", "01111982", "01101983", "01091991", "01081981", "01081975", "01061981", "01051991", "01031994", "01011958", "watching", "tryagain", "theclash", "terrence", "terrance", "stefania", "southside", "solnishko", "smokedog", "sk8ordie", "shitfuck", "Russian7", "rsalinas", "roserose", "rootedit", "reindeer", "regional", "rebbyt34", "r4e3w2q1", "qqqqqqqqqq", "qazwsxedc1", "premiere", "optiplex", "nokia5230", "nickolas", "mystical", "monkeyma", "momsanaladventure", "MICHELLE", "maryanne", "marketing", "marketin", "marishka", "mackenzi", "laracroft", "lagwagon", "kevin123", "Jessica1", "ironhors", "information", "hotbabes", "hornyguy", "homeless", "hogwarts", "hernande", "headless", "Hd764nW5d7E1vb1", "hamburger", "grandpri", "goodfell", "golfclub", "gobigred", "fuckedup", "everquest", "evergree", "ericeric", "envision", "eightbal", "doggydog", "dhjnvytyjub", "detroit1", "database", "dangerou", "computers", "citibank", "choppers", "cannonda", "callofduty", "bullwink", "brunette", "bravehea", "bookcase", "blackcock", "beepbeep", "bassbass", "armstrong", "antigone", "abstract", "987654321q", "369852147", "31081994", "31071981", "31051984", "31031981", "30111984", "30101989", "30081991", "30011976", "29121993", "29111980", "29101993", "29061992", "29051982", "29051980", "29041991", "29031995", "28101987", "28061992", "28021993", "27121987", "27121984", "27101993", "27081983", "27061992", "27061986", "27051982", "27041982", "27021983", "26111979", "26091980", "26071993", "26061988", "26061984", "26051982", "26031981", "25111979", "25101992", "25101984", "25041982", "25041981", "25041977", "25021993", "25021982", "25011992", "24121983", "24111980", "24111979", "24091979", "24041982", "24021981", "24011979", "23121992", "23081982", "23071987", "23041981", "23031993", "23031978", "22111978", "22071993", "22061980", "22031994", "22031988", "21111991", "21101978", "21031994", "20121983", "20101981", "20091995", "20091992", "20081992", "20041993", "20031976", "20021994", "19531953", "19121994", "19121993", "19121991", "19101977", "19081989", "19051991", "19041991", "19031993", "19031992", "19031988", "19031984", "19021989", "18121991", "18101979", "18091992", "18081980", "18011982", "17171717aa", "17111990", "17111983", "17081994", "16121977", "16111993", "16111980", "16061982", "16051996", "16031984", "15121991", "15091984", "15081979", "15081978", "15071993", "15051979", "15051978", "15041978", "15031981", "147896321", "14101981", "14071981", "14061995", "14051989", "14041983", "14031972", "14021979", "14021978", "13111981", "13091991", "13031993", "13031982", "13021983", "12s3t4p55", "123qweas", "12121979", "12111979", "12081980", "12071979", "12061983", "12021979", "12011994", "11121979", "11121978", "11071992", "11071982", "11071979", "11061990", "11061979", "11051977", "11021986", "11021979", "11011978", "10111980", "10091990", "10091987", "10091982", "10081979", "10071977", "10061982", "10051991", "10041988", "09121984", "09111986", "09111984", "09101979", "09091981", "09061992", "09061982", "09031983", "09021992", "09021979", "09011986", "08101990", "08101983", "08091991", "08091990", "08081987", "08031978", "08011991", "07121977", "07111992", "07071991", "07061987", "07051991", "07031990", "07021982", "07021981", "07011981", "06091983", "06091982", "06081982", "06081981", "06071976", "06061978", "06031993", "06031981", "06021980", "06021979", "05121979", "05111988", "05111987", "05101981", "05081984", "05031993", "05031980", "05011986", "04121983", "04041994", "04041980", "04031993", "04031992", "04031983", "04031980", "04021983", "03121989", "03111980", "03051983", "03021981", "02121991", "02111988", "02101991", "01121978", "01071994", "01021982", "01021981", "01021976", "01011964", "ZZ8807zpl", "youandme", "yfnfitymrf", "woodside", "volkodav", "vfnbkmlf", "triplets", "timothy1", "timelord", "thriller", "tenerife", "techniques", "takamine", "sweetass", "shotokan", "sexsexse", "SAMANTHA", "rushrush", "rocky123", "qwerty78", "pyramids", "prelude1", "potatoes", "pornpass", "phaedrus", "peternorth", "patrizia", "password11", "passwerd", "panorama", "nokia5130", "nemesis1", "natascha", "music123", "muffdive", "motorcyc", "misiaczek", "MERCEDES", "maximilian", "marriott", "madonna1", "macintosh", "kristen1", "killzone", "jakester", "insertions", "insertion", "impalass", "ijrjkflrf", "helpless", "hardwork", "gulliver", "grapeape", "goodwill", "ginscoot", "ghjnjnbg", "genocide", "fynjybyf", "flashman", "feetfeet", "facefuck", "evanescence", "ethernet", "elvis123", "dragon11", "domestic", "coolgirl", "cocktail", "chauncey", "cezer121", "caterina", "carlotta", "callahan", "bruno123", "bobmarle", "bloopers", "blackcoc", "baywatch", "asdfjkl;", "archangel", "anthony2", "8PHroWZ622", "78963214", "69213124", "67camaro", "50505050", "4rfv3edc", "31101992", "31081992", "31081991", "31071992", "31071978", "31011978", "30121989", "30121982", "30111993", "30091991", "30091990", "30081980", "30071980", "30051990", "30031982", "30011981", "29111991", "29091994", "29091979", "29081992", "29081984", "29081979", "29071984", "29051976", "28101990", "28101984", "28101981", "28091979", "28081992", "28081987", "28041984", "28021994", "27121980", "27101984", "27101982", "27101980", "27091981", "27091980", "27061991", "27061987", "27041992", "27041981", "27021993", "27021989", "27021981", "26101979", "26081991", "26061977", "26021993", "25051975", "24111978", "24071985", "24061983", "24051983", "24041978", "24021982", "24011994", "23121993", "23121981", "23101989", "23101983", "23071980", "23061981", "23021980", "22121980", "22111984", "22101986", "22081984", "22061983", "22051979", "22021983", "22011980", "21121993", "21091981", "21071991", "21071981", "21071980", "21061979", "21041982", "21041980", "21021981", "20111993", "20111980", "20101979", "20091981", "20091979", "20081998", "20071979", "20051982", "20021978", "1hxboqg2", "19111983", "19071987", "18121981", "18111980", "18071985", "18061978", "18031987", "17111994", "17101984", "17081979", "17071981", "17061980", "17041978", "17031981", "16121984", "16121978", "16091993", "16081982", "16071990", "16071976", "16051992", "16021978", "15111994", "15091979", "15081974", "15061975", "15021992", "14531453", "14121982", "14101982", "14091992", "14081995", "14071994", "14071991", "14071982", "14061992", "14061978", "14041990", "14041977", "13091994", "13091981", "13081989", "13071981", "13031979", "13021980", "13011980", "123masha", "123hfjdk147", "123456789k", "123456789012", "12111989", "12101991", "12091994", "12061993", "12011978", "11121993", "11101992", "11051993", "11041977", "11011994", "11011984", "11011983", "10111992", "10101968", "10081994", "10021980", "09121988", "09101987", "09061993", "09061985", "09051992", "09051982", "09051980", "09041993", "09031984", "08101993", "08101991", "08071981", "08061993", "08061980", "08051978", "08041991", "08021981", "08011993", "07071981", "07051979", "07041993", "07041991", "07031980", "07011984", "06121993", "06101984", "06051981", "06051976", "06041983", "05121987", "05071992", "05061992", "05021979", "04051992", "03111982", "03101987", "03071988", "03041979", "03041977", "03031980", "03021983", "02111991", "02021996", "02021995", "02011991", "01230123", "01121983", "01101993", "01061994", "01061980", "01031979", "zxcvvcxz", "yesterda", "windows1", "volkswagen", "vaseline", "uhbujhbq", "tomservo", "Thunder1", "thesaint", "ssssssssss", "splatter", "sonyvaio", "soccer13", "snowman1", "snoopdogg", "snakeman", "saunders", "russell1", "robinhood", "polaroid", "pokemon123", "p455w0rd", "openopen", "open1234", "novifarm", "newpass1", "mysecret", "montecarlo", "momomomo", "milhouse", "mayfield", "luv2epus", "loveyou2", "lexingky", "lemmings", "kennwort", "jason123", "iloveporn", "hotchick", "homer123", "hilfiger", "hennessy", "heather2", "hawkwind", "happydog", "gregory1", "greatsex", "gotigers", "gooseman", "giveitup", "ganjaman", "fred1234", "francesca", "fordf250", "federica", "eleven11", "dropdead", "doggystyle", "devilmaycry", "destroyer", "deborah1", "davidoff", "darthvader", "dadadada", "Corvette", "contains", "colossus", "claudine", "cheyanne", "catholic", "catdaddy", "cambridge", "buttbutt", "boogaloo", "bernhard", "barbara1", "assclown", "aquarium", "angeline", "adventur", "5tgb6yhn", "5hsU75kpoT", "34523452", "3216732167", "31121989", "31031992", "31031978", "31011980", "30121992", "30101992", "30101980", "30041981", "30031990", "30031981", "30031976", "30011984", "29111990", "29111977", "29061993", "29051983", "28121992", "28111980", "28071992", "28041985", "28031992", "28021995", "28021975", "28011993", "28011977", "28011974", "27121983", "27101977", "27091986", "27081979", "27071993", "27071981", "27061982", "27041994", "26071980", "26041982", "26041978", "25121993", "25101982", "25081992", "25081990", "25061993", "25061982", "25041993", "25011978", "24111986", "24101982", "24091992", "24091976", "24081983", "24071978", "24051982", "24031994", "24021978", "23061994", "23041980", "23031994", "22091992", "22051993", "22041980", "22031979", "22021978", "21091977", "21081984", "21081976", "21051992", "21031977", "21021980", "21011980", "20121991", "20121979", "20111992", "20111983", "20081980", "20041982", "20031982", "20031979", "19191919", "19111993", "19111991", "19101994", "19071977", "19061981", "19051978", "19041984", "19031981", "19021981", "19011992", "19011983", "18121982", "18081984", "18071984", "18071982", "18061979", "18051995", "18041981", "18041979", "18031990", "18021994", "18021983", "17121982", "17101981", "17091993", "17061981", "17041993", "17021994", "17011995", "17011993", "16121980", "16121976", "16091994", "16091981", "16081994", "16061993", "16051982", "16051978", "16021992", "15121981", "15101993", "15061981", "15051984", "15031978", "15031976", "14101979", "14091993", "14081981", "14071992", "14061979", "13081994", "13051984", "13041980", "13011979", "123456abc", "12121993", "12121978", "12111992", "12101992", "12061982", "12061978", "12051995", "12041975", "12031980", "12031978", "12011983", "12011976", "11121988", "11111981", "11071978", "11061978", "11051994", "11051981", "11041994", "11041979", "11031981", "10121983", "10111984", "10081978", "10071992", "10071979", "10051979", "10041980", "10031975", "100200300", "10011994", "09121976", "09111990", "09101981", "09081991", "09081978", "09041980", "09041975", "09011982", "085tzzqi", "08121992", "08111980", "08091979", "08081974", "08021993", "07111981", "07091980", "07071979", "07061989", "07061977", "07051983", "07041978", "07021978", "07011990", "063dyjuy", "06111988", "06081978", "06051982", "06031995", "06021990", "06011992", "06011976", "05091989", "05091983", "05081982", "05071979", "05061993", "05051994", "05031982", "05011980", "04101987", "04081990", "04071979", "04061976", "04041977", "04031986", "04021989", "04011982", "03121979", "03111985", "03101992", "03081986", "02121987", "02121984", "02071992", "01478520", "01101978", "01071979", "01051982", "01051981", "01021993", "0102030405", "yamahar6", "waterpolo", "vladvlad", "valentino", "ultraman", "topsecre", "thelast1", "tanechka", "supernatural", "summertime", "salvator", "saab9000", "romaroma", "romanova", "rickster", "raindrop", "qwerty77", "qazwsxedcrfvtgb", "princeto", "pegasus1", "opensesame", "newhouse", "nbuhtyjr", "minnesota", "mattingl", "mandolin", "maddison", "lotus123", "Liverpoo", "lincoln1", "letsplay", "lebron23", "julieann", "ironman1", "guesswho", "gfhjkm12", "getsdown", "georgia1", "gbgbcmrf", "foxhound", "flipmode", "fireman1", "fastcars", "falstaff", "evergreen", "dutchman", "duckhunt", "distance", "deathrow", "daffodil", "cvbhyjdf", "cumeater", "crocodil", "creatine", "christel", "chastity", "cbr600rr", "calcutta", "buratino", "buffalos", "bradshaw", "bluedevi", "blackboy", "blackass", "bignasty", "beaumont", "badkarma", "astalavista", "anteater", "amoremio", "allright", "alligator", "8PHroWZ624", "74185296", "44magnum", "32165498", "31101975", "31071993", "31071976", "31011991", "31011984", "31011976", "30121980", "30111991", "30091979", "30091978", "30071984", "30071981", "30041978", "29111981", "29061980", "29051981", "28091983", "28071976", "28061993", "28061987", "28051979", "28041975", "28011980", "27121977", "27081993", "27071979", "27071977", "27061981", "27031982", "27031981", "27011991", "26262626", "26121995", "26121992", "26081984", "26071994", "26051991", "26031993", "26011995", "258258258", "25111983", "25091978", "25091976", "25081979", "25071982", "25051976", "24121979", "24071979", "24061982", "24041979", "24011993", "24011978", "23111981", "23111979", "23091993", "23071977", "23031981", "23021979", "22121991", "22111975", "22091978", "22081980", "22061993", "22061977", "22031992", "22021977", "21121979", "21081983", "21071979", "21061982", "21031982", "21021982", "21021976", "20121976", "20111988", "20111978", "20111974", "20101978", "20051994", "1Letmein", "19111992", "19091989", "19051974", "19031991", "19011984", "19011976", "18051994", "18051983", "18041993", "18031992", "18021978", "17101983", "17081981", "17051980", "17031978", "17011979", "16121994", "16111991", "16091983", "16081993", "16081981", "16081978", "16051983", "16011993", "15121980", "15101977", "15021982", "15011978", "14321432", "14121994", "14091985", "14081979", "14071993", "14031983", "14031981", "14011993", "13791379", "1357913579", "13121992", "13121981", "13101981", "13101980", "13051978", "13041982", "13041979", "13041978", "13021982", "123qwe456", "123456asd", "123456ab", "12345432", "12121975", "12101980", "12081982", "12061995", "12051994", "12041981", "12041979", "12031995", "12011982", "11091981", "11081981", "11071981", "10061993", "10061979", "10031979", "10011981", "09071975", "09051979", "09041983", "09031993", "09021983", "09011983", "08121990", "08081980", "08051991", "08041987", "08031976", "08021982", "08011992", "08011985", "07121981", "07111990", "07111988", "07091994", "07091977", "07081975", "07061983", "07031981", "06051980", "06041993", "06011995", "06011994", "06011983", "05121980", "05101993", "05101985", "05101979", "05081980", "05041977", "05021986", "04111984", "04091982", "04071994", "04061992", "04051976", "04051975", "04031981", "04031977", "04021980", "03121977", "03111983", "03101980", "03041993", "03041982", "03011980", "02091992", "02032009", "01121981", "01111981", "01101981", "01092011", "01081979", "01061977", "01051977", "01051976", "01051970", "01012005", "zxzxzxzx", "zolushka", "whoopass", "westlife", "wellhung", "wasdwasd", "warehous", "waffenss", "vineyard", "vicecity", "vfylfhby", "vergeten", "vegas123", "usmc0311", "ufhvjybz", "trucker1", "transfor", "tooltool", "thornton", "teamwork", "swallows", "summerti", "stewart1", "steve123", "stamford", "spartan117", "solidsnake", "sixtynin", "service1", "seraphim", "satellit", "sasasasa", "ronaldo7", "rerfhfxf", "rerehepf", "remington", "redshift", "redneck1", "redbeard", "qwerty777", "qaz12345", "professor", "postov1000", "politics", "polarbea", "pimpster", "payton34", "patterso", "pantyhose", "palomino", "outoutout", "onepiece", "nyyankee", "nolimits", "ninanina", "nicknick", "newport1", "monkey11", "metalgear", "meltdown", "mccarthy", "mattmatt", "Matthew1", "masterkey", "manhattan", "magnavox", "loglatin", "lifeisgood", "licorice", "learning", "lalaland", "lakers24", "kitty123", "kingsize", "jimmy123", "invictus", "Gy3Yt2RGLs", "goodness", "goodison", "glassman", "ghjvtntq", "felicity", "failsafe", "fabrizio", "f15eagle", "excellen", "emmitt22", "element1", "dumpster", "divorced", "dillweed", "deepblue", "counterstrike", "coolbean", "commerce", "collecti", "chillout", "chemistr", "carefree", "capital1", "calculus", "calamity", "caffeine", "buchanan", "black123", "bigpussy", "bigdick1", "barakuda", "babushka", "asmodeus", "asdfg12345", "aquafina", "angelito", "alexandru", "a1a2a3a4a5", "52525252", "48151623", "31081986", "31081981", "31071987", "31071979", "31051981", "31031979", "31011982", "31011979", "30081993", "29111986", "29101981", "29091992", "29091978", "29071979", "29051979", "28121991", "28101993", "28101983", "28091994", "28081993", "28051978", "28041993", "28041977", "27121992", "27121985", "27101988", "27091994", "27091978", "27081992", "27071992", "27021979", "27011993", "27011980", "26111990", "26101991", "26101978", "26091982", "26081982", "26071981", "26061993", "26051981", "25111981", "25071993", "25061977", "25021981", "24121980", "24081979", "24061977", "24041981", "24021980", "24011980", "23121980", "23091980", "23081981", "23071996", "23071978", "23061993", "23061978", "23031979", "23021995", "23021994", "23011995", "23011993", "22121993", "22111992", "22101980", "22081988", "22071976", "22061976", "22051995", "22031980", "22011981", "21121990", "21101995", "21081982", "21081979", "21041981", "21011993", "21011979", "20121980", "20121977", "20111981", "20071980", "20061979", "20061977", "1Mustang", "19061979", "19051992", "19031979", "19011994", "18091981", "18081991", "18071992", "18041978", "18031984", "18031978", "17931793", "17121981", "17091988", "17081983", "17081976", "17071993", "17061972", "17031977", "17021995", "17021978", "17021974", "16101990", "16071996", "16051995", "16051980", "16051979", "16041980", "16031982", "16011978", "15121978", "15121973", "15031979", "15021980", "15011980", "14101980", "14101975", "14021993", "13572468", "13091983", "13051982", "13051981", "12451245", "12345678901", "123321456", "12101981", "12071970", "12041961", "12031983", "11091982", "11091977", "11071994", "10101995", "10101994", "10091981", "10061994", "10061978", "10021992", "10021977", "10021976", "10011975", "10011970", "09121981", "09111982", "09101992", "09081981", "09061980", "09061977", "09051973", "08520852", "08111978", "08081978", "08071993", "08051982", "08011974", "07121990", "07111980", "07101994", "07091991", "07061992", "07031995", "07031982", "06121984", "06121981", "06111992", "06101992", "06091980", "06091979", "06071981", "06061992", "06051994", "06041985", "06041981", "06031994", "06011981", "05121993", "05111981", "05091990", "05071980", "05071971", "05041995", "05041979", "05031994", "05021992", "05021983", "05021982", "04121978", "04101994", "04081976", "04071991", "04031987", "04021994", "04021977", "04011983", "03121981", "03091993", "03091989", "03071979", "03061995", "03061980", "03032009", "03031976", "03021991", "03021980", "03011993", "02121979", "02111981", "02061994", "02061991", "02022008", "01111980", "01111979", "01071993", "01061978", "01061975", "01021996", "01011969", "01011963", "01011955", "yorktown", "yesterday", "worldcup", "winchest", "valdepen", "universi", "unicorn1", "thunderbird", "thematri", "tecumseh", "teacher1", "summer01", "suikoden", "smuggles", "skateboa", "sideways", "showboat", "sebastie", "scruffy1", "schastie", "sandydog", "sailfish", "qwaszx12", "qazxsw12", "!QAZ2wsx", "pussylov", "psychnau", "professional", "prashant", "powerade", "pontiac1", "pinkpink", "peregrin", "pennstate", "parsifal", "overload", "omsairam", "october2", "novikova", "nadezhda", "mymother", "mustang9", "mustang8", "mustang0", "moonshine", "mindless", "michele1", "metropol", "mauricio", "master01", "marigold", "manager1", "luscious", "luckyman", "LoveMe89", "longlegs", "longhorns", "lollollol", "letmein22", "lancaste", "kicksass", "joshua12", "johndeere", "jeffjeff", "jeepjeep", "jediknight", "ilya1992", "illumina", "hotsauce", "hometown", "holahola", "hitman47", "hermione", "hellohello", "hatteras", "gunsling", "goldfinger", "glenwood", "ghjcnjghjcnj", "gfhjkzytn", "fuckyeah", "footlove", "finnegan", "favorite8", "favorite7", "fabienne", "elbereth", "dustydog", "ducksoup", "drjynfrnt", "dragon13", "douglas1", "dominica", "dkflbvbhjdbx", "delivery", "davecole", "copenhagen", "control1", "consuelo", "clitlick", "claudia1", "chipper1", "champions", "celticfc", "caseydog", "camelot1", "cableguy", "brownies", "boris123", "bonghits", "bluebear", "blackbel", "billiard", "bigbutts", "bachelor", "avangard", "angelofwar", "andrew12", "amarillo", "alphaman", "alabama1", "admin18533362", "89898989", "7hrdnw23", "65656565", "333666999", "31031983", "31011993", "30111995", "30111992", "30101978", "30101974", "30091984", "30081994", "30061978", "30051978", "29101983", "29031994", "29031992", "29031981", "28282828", "28121993", "28121980", "28101977", "28101974", "27111983", "27111981", "27081980", "27071975", "27061975", "27041991", "26121980", "26071978", "26061994", "26051994", "26031976", "26021981", "25121977", "25101993", "25101981", "25041995", "25011995", "25011980", "24862486", "24101981", "24081993", "24061981", "24041995", "24021992", "23121977", "23111980", "23091979", "23051993", "22101993", "22091993", "22091980", "22091979", "22071978", "22041994", "22041978", "22041974", "22031982", "21111975", "21081992", "21061981", "21031979", "21021994", "21021979", "21011982", "20091994", "20081996", "20061974", "20051977", "20011995", "1qaz!QAZ", "1Basebal", "1a2a3a4a5a", "19451945", "19101981", "19081981", "19081975", "19071992", "19061974", "19031976", "19011995", "19011977", "18091994", "18071994", "18051981", "18041980", "18011995", "18011980", "17121989", "17121975", "17111993", "17101995", "17101978", "17091994", "17071994", "17021975", "17011981", "16101983", "16101976", "16071981", "16061995", "16051994", "16041979", "16041977", "16031981", "159753123", "151nxjmt", "15121994", "15111978", "15101978", "15091993", "15081977", "15071994", "15051977", "15021972", "14111981", "14091981", "14091980", "14071976", "14021975", "13576479", "13101979", "13091978", "13061980", "13051996", "13011995", "13011994", "12qwerty", "12121973", "12121970", "12101975", "12091978", "12081978", "12061996", "12051975", "12041992", "12031977", "12031974", "11111975", "11091993", "11091980", "11031979", "11031975", "11021978", "11021974", "10121981", "10111995", "10111978", "10061977", "10031972", "09111992", "09101990", "09091977", "09081983", "09071980", "09061978", "09031980", "08101988", "08061991", "08061982", "08051980", "08021983", "07121986", "07101991", "07101979", "07091992", "07091979", "07061981", "06121992", "06101994", "06091995", "06091981", "06081980", "06071977", "06061975", "06051984", "06041992", "06041982", "06031982", "05121981", "05091979", "05091977", "05071982", "05071978", "05051995", "05041993", "05031985", "05021984", "05011976", "04200420", "04121990", "04101982", "04081993", "04061983", "04051995", "04041974", "03121991", "03111988", "03071977", "03051977", "03031979", "03021994", "03011995", "02121993", "02081995", "02071993", "02061995", "01121991", "01111985", "01101992", "01092000", "01081993", "01071992", "01041994", "01041976", "01011962", "01011957", "ytrhjvfyn", "yodayoda", "wolfwolf", "whatever1", "vthctltc", "vfvfvskfhfve", "touchdow", "thomas12", "thematrix", "theflash", "tactical", "strannik", "stampede", "slayer666", "sixtynine", "shadow01", "searcher", "satriani", "saopaulo", "rockroll", "rhfcfdxbr", "red12345", "Q1w2e3r4", "pyramid1", "prisoner", "polniypizdec0211", "pleaseme", "pleasant", "playboys", "Phoenix1", "pepsi123", "pedersen", "passions", "parasite", "overtime", "oriflame", "nokian70", "nevermor", "mousepad", "moonstar", "mobbdeep", "milenium", "michael9", "mapet123456", "mammamia", "mackenzie", "machoman", "lovesexy", "lovefeet", "lostsoul", "longtime", "longdick", "lionlion", "Lineage2", "limpbizkit", "legoland", "language", "kurosaki", "kirkwood", "kilkenny", "juvenile", "junkyard", "joseluis", "jbond007", "iwantyou", "indonesia", "ibilljpf", "hugohugo", "henderson", "headshot", "gtkmvtym", "greyhoun", "goodtimes", "goldmine", "goldgold", "ghjnjrjk", "ghbdtn12", "general1", "funnyman", "freeland", "forklift", "flintsto", "fkmnthyfnbdf", "essendon", "emachines", "dragon99", "darkmoon", "damage11", "daisymae", "covenant", "corporal", "cordelia", "codeblue", "claypool", "catalyst", "carthage", "bumblebe", "buckbuck", "broodwar", "boscoe01", "bondarenko", "birthday1", "besiktas", "bayliner", "baphomet", "avengers", "atlanta1", "assassins", "arsenalfc", "aqualung", "anatoliy", "algernon", "aleksander", "afrodita", "Abcd1234", "aa123456", "90909090", "89600506779", "61586158", "54545454", "33rjhjds", "31081993", "30081985", "30061975", "30051983", "30051982", "2wsxzaq1", "29121977", "29051995", "29051978", "29041979", "29041976", "29041974", "29031980", "29011977", "28121975", "28111994", "28091977", "28041995", "28041978", "27111980", "27091992", "27081991", "27081982", "27081981", "27041995", "27031980", "27011995", "27011977", "26121982", "26091983", "26091978", "26071995", "26061982", "26041993", "26041980", "26021978", "25121992", "25111984", "25111977", "25091996", "25091980", "25061980", "246813579", "24121991", "24111993", "24111976", "24091983", "24061993", "24061980", "24051981", "24051980", "24031977", "23101993", "23091975", "23081995", "23011978", "23011975", "22121994", "22111994", "22101979", "22091994", "22071980", "22061979", "22061978", "22021993", "22011994", "21091994", "21071993", "21041975", "21031978", "21021978", "21011995", "20121993", "20121981", "20101980", "20071994", "20061993", "20051978", "20021976", "20011993", "20011976", "19561956", "19111982", "19111979", "19091981", "19071981", "19031983", "19011980", "19011975", "18111993", "18111991", "18111975", "18101994", "18101993", "18081978", "18031983", "18031977", "18021980", "17051974", "17021980", "17011996", "17011980", "16091989", "16081976", "16071984", "16051977", "16041981", "16021981", "16021975", "16011976", "159753852", "15111992", "15091982", "15081981", "15061980", "14921492", "14121992", "14121981", "14121978", "14101976", "14081973", "14071979", "14071978", "14061976", "14041979", "14031994", "14031993", "14031979", "14021994", "14011995", "14011981", "14011979", "13121993", "13111992", "13111983", "13101991", "13091992", "13071995", "13041975", "13031995", "13031978", "13021981", "123456qq", "12111980", "12101994", "12071993", "12061977", "12051978", "12031981", "12031976", "12021977", "12021974", "11101994", "11101977", "11101976", "11081995", "11061977", "10101972", "10091973", "10041977", "10031994", "10021979", "10011977", "09121991", "09121980", "09091992", "09091983", "09081979", "09041992", "09041976", "09021981", "08121980", "08111977", "08081977", "08071975", "08031979", "07101981", "07101962", "07081979", "07051982", "07041992", "07031992", "07021992", "06121978", "06101977", "06091986", "06081976", "06061974", "06021993", "05101992", "05071994", "05061979", "05041980", "05021978", "05011982", "04111983", "04111980", "04101983", "04091992", "04031988", "04031975", "04021991", "04011984", "03121988", "03061993", "03041976", "03031995", "03031978", "02111993", "02051994", "02051993", "01121992", "01111978", "01111977", "01101975", "01091993", "01041977", "01022011", "01021975", "01012008", "zxcvb12345", "zcxfcnkbdf", "ytyfdbcnm", "wonderland", "wisconsi", "william2", "viper123", "valdemar", "trojans1", "trader12", "timetime", "timeless", "tigger12", "thissuck", "theworld", "tennessee", "stockings", "sobriety", "snoogans", "skypilot", "sk84life", "sidewind", "shadow11", "schwartz", "schnuffi", "schneider", "Rush2112", "rockydog", "rjyatnrf", "qwertzui", "qwerfdsa", "qazxswedcvfr", "q1234567890", "pussylover", "princessa", "popsicle", "planning", "phoenix2", "password3", "%%passwo", "passfind", "parliament", "oscar123", "orange12", "oldschool", "nonrev67", "nikenike", "milashka", "marietta", "makemoney", "lucas123", "lindsay1", "leningrad", "kovalenko", "kingrich", "Jonathan", "investor", "iloveher", "hrvatska", "hammerhe", "gunsmoke", "goodstuf", "ghtktcnm", "ghbrjkbcn", "ghblehrb", "gfhfljrc", "germany1", "galatasaray", "fuckyou123", "fuckfest", "forgiven", "flhtyfkby", "flapjack", "firework", "firestor", "fightclub", "exploite", "elisabeth", "dripping", "dreamers", "dreamer1", "discount", "cynthia1", "cyberonline", "critical", "charlies", "c3por2d2", "buttplug", "bulldawg", "buckeye1", "blacksun", "bigpimpi", "barracuda", "barracud", "babababa", "azsxdcfvgb", "astroboy", "art131313", "arabella", "appleton", "annabelle", "ambition", "akatsuki", "agnieszka", "advocate", "adelaida", "adamadam", "abcdefghi", "777888999", "36363636", "31081984", "31051994", "31011988", "30111978", "30091981", "30091977", "30081981", "30011982", "29121978", "29091976", "29061976", "29031996", "29031977", "29021992", "28121994", "28081980", "28081979", "28071979", "28051976", "28021982", "27111979", "27101981", "27071980", "27061995", "27061993", "27061979", "27061976", "27051981", "27051980", "27051976", "27051975", "27041978", "27031978", "27031976", "27011992", "27011976", "26121994", "26101980", "26081994", "26071976", "26071974", "26061980", "26021982", "26021979", "26021977", "26011994", "25081982", "25031981", "25011981", "24121992", "24111975", "24081981", "24071980", "24071974", "24061979", "24061975", "24051977", "24041994", "24041980", "23176djivanfros", "23091977", "23011994", "23011976", "22111976", "22081996", "22081994", "22081982", "22071995", "22071994", "22071979", "22071977", "22061996", "22041970", "22031993", "21091993", "21071978", "21061975", "21051994", "21051980", "21041979", "21021993", "20121992", "20121975", "20111979", "20091980", "20091978", "20081981", "20051975", "20021979", "20011977", "1qay2wsx", "19121979", "19121977", "19111980", "19111977", "19101976", "19091977", "19081980", "19051995", "19051982", "19021978", "18091990", "18091979", "18081981", "18061977", "18041982", "17091990", "17091989", "17091980", "17091976", "17071979", "17071977", "17041981", "17041974", "17011978", "16121993", "16081996", "16071979", "16061978", "16031995", "16011996", "16011995", "15111983", "15111979", "15091991", "15081982", "15071978", "15061982", "15021994", "15021979", "15021977", "15021976", "14081980", "14081977", "14061994", "14041980", "14031992", "14021976", "14011974", "13121975", "13111978", "13091976", "13081976", "13061995", "13061993", "13061978", "13051980", "13041994", "13011975", "1234567u", "123456789qwerty", "123456789n", "123321qwe", "12233445", "12091993", "12091979", "12081996", "12071995", "12051976", "12021996", "111111111111", "11091996", "11091979", "11061975", "11051992", "11041975", "11011993", "10121975", "10101970", "10091975", "10071978", "10051982", "10051980", "10041994", "10031995", "10031982", "10021973", "09071993", "09071976", "09061979", "09061975", "09061972", "09051977", "09031982", "08154711", "08111989", "08111979", "08101982", "08091977", "08071980", "08061977", "08051988", "08051977", "08041993", "08041977", "08031984", "08031973", "08021987", "08021976", "08011981", "07121980", "07111983", "07111978", "07051977", "07031996", "07031983", "07011994", "06121990", "06111993", "06101993", "06101990", "06101983", "06101978", "06091992", "06091976", "06081977", "06071979", "06061977", "06051975", "06031980", "06021991", "05121978", "05091982", "05091981", "05081993", "05081990", "05011991", "05011979", "04091988", "04091984", "04091983", "04091978", "04081988", "04081980", "04061975", "03121993", "03121992", "03091995", "03091994", "03081981", "03081977", "03081975", "03051992", "02121982", "02121977", "02111980", "02111978", "02101992", "02081992", "02051996", "01121994", "01091995", "01091981", "01071976", "01051975", "01031977", "01021979", "01021974", "01011959", "zzzzzzzzzz", "zaq1xsw2cde3", "westham1", "westcoast", "weedweed", "wargames", "w1w2w3w4", "voltaire", "venezuel", "titlover", "thorsten", "thinkpad", "thetachi", "thejoker", "televizor", "tazdevil", "sweethea", "summer12", "stroller", "stinger1", "steelhea", "southsid", "sonnyboy", "smallville", "slimed123", "shipping", "save13tx", "ryanryan", "ruthless", "rocketman", "robinhoo", "repytwjdf", "redhead1", "reaction", "ranchero", "Qq123456", "pussylicker", "psychnaut1", "prospero", "primetim", "prettygirl", "porn4life", "playoffs", "pizzapie", "pheasant", "peter123", "olgaolga", "october1", "oc247ngUcZ", "nonsense", "nokia5300", "nokia3250", "nighthaw", "newworld", "nacional", "mustang3", "mostwanted", "mosquito", "moonmoon", "monique1", "miranda1", "minotaur", "Michigan", "michael8", "metalica", "medicina", "mavericks", "Marshall", "margosha", "lindsey1", "lavender", "laracrof", "lapdance", "ladygaga", "kochanie", "kochamcie", "knockout", "killemall", "karamelka", "jerusalem", "jedimast", "iwantsex", "isacs155", "ironmaid", "interpol", "internat", "inflames", "indahous", "hornyboy", "hondacivic", "hellokit", "hannover", "handcuff", "hallmark", "halfmoon", "gremlins", "ganjubas", "galadriel", "galactic", "frontera", "freiheit", "francis1", "faulkner", "fatluvr69", "fantastic", "evgeniya", "epaulson", "edwardss", "ducati99", "dkflbvbhjdyf", "dickface", "danielit", "crossbow", "chimchim", "champagn", "camaroz2", "bugsbunny", "bluegill", "blondie1", "blingbling", "blastoff", "biggdogg", "behemoth", "bareback", "badlands", "backspac", "Babylon5", "asd12345", "arsehole", "argonaut", "antoshka", "antonio1", "allstars", "alexandria", "account1", "987412365", "96969696", "748159263", "326159487", "31313131", "31121993", "31121981", "31101979", "31081980", "31051980", "31031993", "31031991", "30121979", "30121978", "30101975", "30091980", "30081978", "30071977", "30061994", "30061976", "30051995", "30041977", "30031994", "30011995", "29121983", "29121979", "29101987", "29101979", "29101976", "29081994", "29031979", "29031976", "28121977", } ret := make(map[string]struct{}) for _, v := range bannedPasswordsList { ret[v] = struct{}{} } return ret } ================================================ FILE: pkg/utils/slice_compare.go ================================================ // nolint: revive package utils func Includes[T comparable](arr []T, against T) bool { for _, v := range arr { if v == against { return true } } return false } func SliceCompare[T comparable](subject []T, against []T) (added []T, missing []T) { for _, v := range subject { if !Includes(against, v) && !Includes(added, v) { added = append(added, v) } } for _, v := range against { if !Includes(subject, v) && !Includes(missing, v) { missing = append(missing, v) } } return } ================================================ FILE: pkg/utils/slice_compare_test.go ================================================ // nolint: revive package utils import ( "reflect" "testing" ) type strSliceTest struct { subject []string against []string expectedAdded []string expectedMissing []string } var strSliceTests = []strSliceTest{ {[]string{"a"}, []string{"b"}, []string{"a"}, []string{"b"}}, {[]string{"a", "b"}, []string{"b"}, []string{"a"}, nil}, {[]string{"a"}, []string{"a", "b"}, nil, []string{"b"}}, {[]string{"a"}, nil, []string{"a"}, nil}, {[]string{"a"}, []string{}, []string{"a"}, nil}, {nil, []string{"b"}, nil, []string{"b"}}, {[]string{}, []string{"b"}, nil, []string{"b"}}, {[]string{"a", "a"}, []string{"b", "b"}, []string{"a"}, []string{"b"}}, {[]string{"a"}, []string{"a"}, nil, nil}, } func TestStrSliceCompare(t *testing.T) { for _, test := range strSliceTests { added, missing := SliceCompare(test.subject, test.against) if !reflect.DeepEqual(added, test.expectedAdded) { t.Errorf("added(%v,%v) = %v; want %v", test.subject, test.against, added, test.expectedAdded) } if !reflect.DeepEqual(missing, test.expectedMissing) { t.Errorf("missing(%v,%v) = %v; want %v", test.subject, test.against, missing, test.expectedMissing) } } } ================================================ FILE: scripts/getDate.go ================================================ //go:build ignore package main import "fmt" import "time" func main() { now := time.Now().Format("2006-01-02 15:04:05") fmt.Printf("%s", now) } ================================================ FILE: sqlc.yaml ================================================ version: "2" sql: - engine: "postgresql" schema: "internal/database/migrations/postgres" queries: "internal/queries/sql" gen: go: package: "queries" out: "internal/queries" sql_package: "pgx/v5" emit_json_tags: true emit_db_tags: true emit_interface: true emit_prepared_queries: false emit_exact_table_names: false emit_empty_slices: true overrides: - db_type: "uuid" go_type: "github.com/gofrs/uuid.UUID" - db_type: "uuid" go_type: "github.com/gofrs/uuid.NullUUID" nullable: true - db_type: "text" go_type: "string" - db_type: "pg_catalog.varchar" go_type: "string" - db_type: "text" nullable: true go_type: type: "string" pointer: true - db_type: "pg_catalog.varchar" nullable: true go_type: type: "string" pointer: true - db_type: "pg_catalog.int4" go_type: "int" - db_type: "serial" go_type: "int" - db_type: "serial" go_type: "int" - db_type: "pg_catalog.timestamp" go_type: "time.Time" - db_type: "pg_catalog.timestamp" nullable: true go_type: type: "time.Time" pointer: true - db_type: "pg_catalog.int4" nullable: true go_type: type: "int" pointer: true - db_type: "jsonb" go_type: "encoding/json.RawMessage" - column: "performers.gender" go_type: "*github.com/stashapp/stash-box/internal/models.GenderEnum" - column: "performers.ethnicity" go_type: "*github.com/stashapp/stash-box/internal/models.EthnicityEnum" - column: "performers.eye_color" go_type: "*github.com/stashapp/stash-box/internal/models.EyeColorEnum" - column: "performers.hair_color" go_type: "*github.com/stashapp/stash-box/internal/models.HairColorEnum" - column: "performers.breast_type" go_type: "*github.com/stashapp/stash-box/internal/models.BreastTypeEnum"