Gisle Aune
6 years ago
32 changed files with 1551 additions and 277 deletions
-
6.idea/misc.xml
-
8.idea/modules.xml
-
6.idea/vcs.xml
-
29.idea/watcherTasks.xml
-
586.idea/workspace.xml
-
217database/mongodb/characters.go
-
51database/mongodb/db.go
-
10database/mongodb/tags.go
-
30go.mod
-
57go.sum
-
4graph2/complexity.go
-
2graph2/gqlgen.yml
-
6graph2/graph.go
-
157graph2/resolvers/character.go
-
14graph2/resolvers/resolvers.go
-
28graph2/types/log.go
-
3internal/auth/permitted.go
-
4models/changekeys/one.go
-
16models/changes/submit.go
-
17models/character.go
-
2models/tag.go
-
14models/tags/db.go
-
26models/tags/list.go
-
19repositories/character.go
-
1repositories/repository.go
-
2repositories/tag.go
-
207services/characters.go
-
224services/loaders/characterloader_gen.go
-
53services/loaders/loaders.go
-
12services/services.go
-
2services/tags.go
-
7tools.go
@ -0,0 +1,6 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project version="4"> |
|||
<component name="JavaScriptSettings"> |
|||
<option name="languageLevel" value="ES6" /> |
|||
</component> |
|||
</project> |
@ -0,0 +1,8 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project version="4"> |
|||
<component name="ProjectModuleManager"> |
|||
<modules> |
|||
<module fileurl="file://$PROJECT_DIR$/.idea/rpdata-api.iml" filepath="$PROJECT_DIR$/.idea/rpdata-api.iml" /> |
|||
</modules> |
|||
</component> |
|||
</project> |
@ -0,0 +1,6 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project version="4"> |
|||
<component name="VcsDirectoryMappings"> |
|||
<mapping directory="$PROJECT_DIR$" vcs="Git" /> |
|||
</component> |
|||
</project> |
@ -0,0 +1,29 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project version="4"> |
|||
<component name="ProjectTasksOptions"> |
|||
<TaskOptions isEnabled="true"> |
|||
<option name="arguments" value="fmt $FilePath$" /> |
|||
<option name="checkSyntaxErrors" value="true" /> |
|||
<option name="description" /> |
|||
<option name="exitCodeBehavior" value="ERROR" /> |
|||
<option name="fileExtension" value="go" /> |
|||
<option name="immediateSync" value="false" /> |
|||
<option name="name" value="go fmt" /> |
|||
<option name="output" value="$FilePath$" /> |
|||
<option name="outputFilters"> |
|||
<array /> |
|||
</option> |
|||
<option name="outputFromStdout" value="false" /> |
|||
<option name="program" value="$GoExecPath$" /> |
|||
<option name="runOnExternalChanges" value="false" /> |
|||
<option name="scopeName" value="Project Files" /> |
|||
<option name="trackOnlyRoot" value="true" /> |
|||
<option name="workingDir" value="$ProjectFileDir$" /> |
|||
<envs> |
|||
<env name="GOROOT" value="$GOROOT$" /> |
|||
<env name="GOPATH" value="$GOPATH$" /> |
|||
<env name="PATH" value="$GoBinDirs$" /> |
|||
</envs> |
|||
</TaskOptions> |
|||
</component> |
|||
</project> |
@ -0,0 +1,586 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project version="4"> |
|||
<component name="ChangeListManager"> |
|||
<list default="true" id="ac85876f-1087-49cc-8c50-039d9d6340d7" name="Default Changelist" comment=""> |
|||
<change afterPath="$PROJECT_DIR$/.idea/misc.xml" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/.idea/modules.xml" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/.idea/vcs.xml" afterDir="false" /> |
|||
<change afterPath="$PROJECT_DIR$/.idea/watcherTasks.xml" afterDir="false" /> |
|||
<change beforePath="$PROJECT_DIR$/database/mongodb/db.go" beforeDir="false" afterPath="$PROJECT_DIR$/database/mongodb/db.go" afterDir="false" /> |
|||
<change beforePath="$PROJECT_DIR$/database/mongodb/tags.go" beforeDir="false" afterPath="$PROJECT_DIR$/database/mongodb/tags.go" afterDir="false" /> |
|||
<change beforePath="$PROJECT_DIR$/go.mod" beforeDir="false" afterPath="$PROJECT_DIR$/go.mod" afterDir="false" /> |
|||
<change beforePath="$PROJECT_DIR$/go.sum" beforeDir="false" afterPath="$PROJECT_DIR$/go.sum" afterDir="false" /> |
|||
<change beforePath="$PROJECT_DIR$/graph2/complexity.go" beforeDir="false" afterPath="$PROJECT_DIR$/graph2/complexity.go" afterDir="false" /> |
|||
<change beforePath="$PROJECT_DIR$/graph2/gqlgen.yml" beforeDir="false" afterPath="$PROJECT_DIR$/graph2/gqlgen.yml" afterDir="false" /> |
|||
<change beforePath="$PROJECT_DIR$/graph2/graph.go" beforeDir="false" afterPath="$PROJECT_DIR$/graph2/graph.go" afterDir="false" /> |
|||
<change beforePath="$PROJECT_DIR$/graph2/resolvers/character.go" beforeDir="false" afterPath="$PROJECT_DIR$/graph2/resolvers/character.go" afterDir="false" /> |
|||
<change beforePath="$PROJECT_DIR$/graph2/resolvers/resolvers.go" beforeDir="false" afterPath="$PROJECT_DIR$/graph2/resolvers/resolvers.go" afterDir="false" /> |
|||
<change beforePath="$PROJECT_DIR$/graph2/types/log.go" beforeDir="false" afterPath="$PROJECT_DIR$/graph2/types/log.go" afterDir="false" /> |
|||
<change beforePath="$PROJECT_DIR$/internal/auth/permitted.go" beforeDir="false" afterPath="$PROJECT_DIR$/internal/auth/permitted.go" afterDir="false" /> |
|||
<change beforePath="$PROJECT_DIR$/models/changekeys/one.go" beforeDir="false" afterPath="$PROJECT_DIR$/models/changekeys/one.go" afterDir="false" /> |
|||
<change beforePath="$PROJECT_DIR$/models/changes/submit.go" beforeDir="false" afterPath="$PROJECT_DIR$/models/changes/submit.go" afterDir="false" /> |
|||
<change beforePath="$PROJECT_DIR$/models/character.go" beforeDir="false" afterPath="$PROJECT_DIR$/models/character.go" afterDir="false" /> |
|||
<change beforePath="$PROJECT_DIR$/models/tag.go" beforeDir="false" afterPath="$PROJECT_DIR$/models/tag.go" afterDir="false" /> |
|||
<change beforePath="$PROJECT_DIR$/models/tags/db.go" beforeDir="false" /> |
|||
<change beforePath="$PROJECT_DIR$/models/tags/list.go" beforeDir="false" /> |
|||
<change beforePath="$PROJECT_DIR$/repositories/repository.go" beforeDir="false" afterPath="$PROJECT_DIR$/repositories/repository.go" afterDir="false" /> |
|||
<change beforePath="$PROJECT_DIR$/repositories/tag.go" beforeDir="false" afterPath="$PROJECT_DIR$/repositories/tag.go" afterDir="false" /> |
|||
<change beforePath="$PROJECT_DIR$/services/services.go" beforeDir="false" afterPath="$PROJECT_DIR$/services/services.go" afterDir="false" /> |
|||
<change beforePath="$PROJECT_DIR$/services/tags.go" beforeDir="false" afterPath="$PROJECT_DIR$/services/tags.go" afterDir="false" /> |
|||
</list> |
|||
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" /> |
|||
<option name="SHOW_DIALOG" value="false" /> |
|||
<option name="HIGHLIGHT_CONFLICTS" value="true" /> |
|||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" /> |
|||
<option name="LAST_RESOLUTION" value="IGNORE" /> |
|||
</component> |
|||
<component name="FileEditorManager"> |
|||
<leaf SIDE_TABS_SIZE_LIMIT_KEY="450"> |
|||
<file pinned="false" current-in-tab="true"> |
|||
<entry file="file://$PROJECT_DIR$/database/mongodb/characters.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="419"> |
|||
<caret line="109" column="4" selection-start-line="109" selection-start-column="4" selection-end-line="109" selection-end-column="4" /> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
</file> |
|||
<file pinned="false" current-in-tab="false"> |
|||
<entry file="file://$USER_HOME$/go/pkg/mod/github.com/globalsign/mgo@v0.0.0-20180403085842-f76e4f9da92e/session.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="539"> |
|||
<caret line="2707" column="14" selection-start-line="2707" selection-start-column="5" selection-end-line="2707" selection-end-column="14" /> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
</file> |
|||
<file pinned="false" current-in-tab="false"> |
|||
<entry file="file://$PROJECT_DIR$/services/characters.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="1632"> |
|||
<caret line="63" column="25" lean-forward="true" selection-start-line="63" selection-start-column="25" selection-end-line="63" selection-end-column="25" /> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
</file> |
|||
<file pinned="false" current-in-tab="false"> |
|||
<entry file="file://$PROJECT_DIR$/models/changekeys/listed.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="288"> |
|||
<caret line="6" column="14" selection-start-line="6" selection-start-column="14" selection-end-line="6" selection-end-column="14" /> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
</file> |
|||
<file pinned="false" current-in-tab="false"> |
|||
<entry file="file://$PROJECT_DIR$/models/changekeys/many.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="816"> |
|||
<caret line="21" column="33" lean-forward="true" selection-start-line="21" selection-start-column="33" selection-end-line="21" selection-end-column="33" /> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
</file> |
|||
<file pinned="false" current-in-tab="false"> |
|||
<entry file="file://$PROJECT_DIR$/models/changekeys/one.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="851"> |
|||
<caret line="25" lean-forward="true" selection-start-line="25" selection-end-line="25" /> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
</file> |
|||
<file pinned="false" current-in-tab="false"> |
|||
<entry file="file://$PROJECT_DIR$/repositories/character.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="576"> |
|||
<caret line="12" column="4" selection-start-line="12" selection-start-column="4" selection-end-line="12" selection-end-column="4" /> |
|||
<folding> |
|||
<element signature="e#22#80#0" expanded="true" /> |
|||
</folding> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
</file> |
|||
</leaf> |
|||
</component> |
|||
<component name="FileTemplateManagerImpl"> |
|||
<option name="RECENT_TEMPLATES"> |
|||
<list> |
|||
<option value="Go File" /> |
|||
</list> |
|||
</option> |
|||
</component> |
|||
<component name="FindInProjectRecents"> |
|||
<findStrings> |
|||
<find>delete(l.cache</find> |
|||
<find>dataloade</find> |
|||
</findStrings> |
|||
</component> |
|||
<component name="GOROOT" path="/usr/lib/go" /> |
|||
<component name="Git.Settings"> |
|||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" /> |
|||
</component> |
|||
<component name="GoLibraries"> |
|||
<option name="indexEntireGoPath" value="false" /> |
|||
</component> |
|||
<component name="IdeDocumentHistory"> |
|||
<option name="CHANGED_PATHS"> |
|||
<list> |
|||
<option value="$PROJECT_DIR$/graph2/graphcore/exec_gen.go" /> |
|||
<option value="$PROJECT_DIR$/database/mongodb/tags.go" /> |
|||
<option value="$PROJECT_DIR$/repositories/tag.go" /> |
|||
<option value="$PROJECT_DIR$/services/services.go" /> |
|||
<option value="$PROJECT_DIR$/services/loaders/characterloader_gen.go" /> |
|||
<option value="$PROJECT_DIR$/graph2/tools.go" /> |
|||
<option value="$PROJECT_DIR$/tools.go" /> |
|||
<option value="$PROJECT_DIR$/repositories/character.go" /> |
|||
<option value="$PROJECT_DIR$/graph2/gqlgen.yml" /> |
|||
<option value="$PROJECT_DIR$/graph2/resolvers/resolvers.go" /> |
|||
<option value="$PROJECT_DIR$/graph2/resolvers/character.go" /> |
|||
<option value="$PROJECT_DIR$/database/mongodb/db.go" /> |
|||
<option value="$PROJECT_DIR$/services/tags.go" /> |
|||
<option value="$PROJECT_DIR$/graph2/complexity.go" /> |
|||
<option value="$PROJECT_DIR$/graph2/types/log.go" /> |
|||
<option value="$PROJECT_DIR$/graph2/graph.go" /> |
|||
<option value="$PROJECT_DIR$/services/loaders/loaders.go" /> |
|||
<option value="$PROJECT_DIR$/internal/auth/permitted.go" /> |
|||
<option value="$PROJECT_DIR$/models/changekeys/many.go" /> |
|||
<option value="$PROJECT_DIR$/models/changekeys/one.go" /> |
|||
<option value="$PROJECT_DIR$/models/token.go" /> |
|||
<option value="$PROJECT_DIR$/models/character.go" /> |
|||
<option value="$PROJECT_DIR$/services/characters.go" /> |
|||
<option value="$PROJECT_DIR$/database/mongodb/characters.go" /> |
|||
</list> |
|||
</option> |
|||
</component> |
|||
<component name="JsFlowSettings"> |
|||
<service-enabled>true</service-enabled> |
|||
<exe-path /> |
|||
<other-services-enabled>true</other-services-enabled> |
|||
<auto-save>true</auto-save> |
|||
</component> |
|||
<component name="ProjectFrameBounds" extendedState="6"> |
|||
<option name="x" value="1220" /> |
|||
<option name="y" value="600" /> |
|||
<option name="width" value="1400" /> |
|||
<option name="height" value="1000" /> |
|||
</component> |
|||
<component name="ProjectLevelVcsManager"> |
|||
<ConfirmationsSetting value="1" id="Add" /> |
|||
</component> |
|||
<component name="ProjectView"> |
|||
<navigator proportions="" version="1"> |
|||
<foldersAlwaysOnTop value="true" /> |
|||
</navigator> |
|||
<panes> |
|||
<pane id="Scope" /> |
|||
<pane id="ProjectPane"> |
|||
<subPane> |
|||
<expand> |
|||
<path> |
|||
<item name="rpdata-api" type="b2602c69:ProjectViewProjectNode" /> |
|||
<item name="rpdata-api" type="462c0819:PsiDirectoryNode" /> |
|||
</path> |
|||
<path> |
|||
<item name="rpdata-api" type="b2602c69:ProjectViewProjectNode" /> |
|||
<item name="rpdata-api" type="462c0819:PsiDirectoryNode" /> |
|||
<item name="database" type="462c0819:PsiDirectoryNode" /> |
|||
</path> |
|||
<path> |
|||
<item name="rpdata-api" type="b2602c69:ProjectViewProjectNode" /> |
|||
<item name="rpdata-api" type="462c0819:PsiDirectoryNode" /> |
|||
<item name="database" type="462c0819:PsiDirectoryNode" /> |
|||
<item name="mongodb" type="462c0819:PsiDirectoryNode" /> |
|||
</path> |
|||
<path> |
|||
<item name="rpdata-api" type="b2602c69:ProjectViewProjectNode" /> |
|||
<item name="rpdata-api" type="462c0819:PsiDirectoryNode" /> |
|||
<item name="services" type="462c0819:PsiDirectoryNode" /> |
|||
</path> |
|||
<path> |
|||
<item name="rpdata-api" type="b2602c69:ProjectViewProjectNode" /> |
|||
<item name="External Libraries" type="cb654da1:ExternalLibrariesNode" /> |
|||
</path> |
|||
</expand> |
|||
<select /> |
|||
</subPane> |
|||
</pane> |
|||
</panes> |
|||
</component> |
|||
<component name="PropertiesComponent"> |
|||
<property name="ASKED_SHARE_PROJECT_CONFIGURATION_FILES" value="true" /> |
|||
<property name="DefaultGoTemplateProperty" value="Go File" /> |
|||
<property name="SHARE_PROJECT_CONFIGURATION_FILES" value="true" /> |
|||
<property name="WebServerToolWindowFactoryState" value="false" /> |
|||
<property name="configurable.Global.GOPATH.is.expanded" value="true" /> |
|||
<property name="configurable.Module.GOPATH.is.expanded" value="false" /> |
|||
<property name="configurable.Project.GOPATH.is.expanded" value="true" /> |
|||
<property name="go.gopath.indexing.explicitly.defined" value="true" /> |
|||
<property name="go.import.settings.migrated" value="true" /> |
|||
<property name="go.sdk.automatically.set" value="true" /> |
|||
<property name="last_opened_file_path" value="$PROJECT_DIR$" /> |
|||
<property name="nodejs_package_manager_path" value="npm" /> |
|||
<property name="settings.editor.selected.configurable" value="reference.settingsdialog.IDE.editor.colors.Color Scheme Font" /> |
|||
</component> |
|||
<component name="RecentsManager"> |
|||
<key name="MoveFile.RECENT_KEYS"> |
|||
<recent name="$PROJECT_DIR$" /> |
|||
</key> |
|||
</component> |
|||
<component name="RunDashboard"> |
|||
<option name="ruleStates"> |
|||
<list> |
|||
<RuleState> |
|||
<option name="name" value="ConfigurationTypeDashboardGroupingRule" /> |
|||
</RuleState> |
|||
<RuleState> |
|||
<option name="name" value="StatusDashboardGroupingRule" /> |
|||
</RuleState> |
|||
</list> |
|||
</option> |
|||
</component> |
|||
<component name="TodoView"> |
|||
<todo-panel id="selected-file"> |
|||
<is-autoscroll-to-source value="true" /> |
|||
</todo-panel> |
|||
<todo-panel id="all"> |
|||
<are-packages-shown value="true" /> |
|||
<is-autoscroll-to-source value="true" /> |
|||
</todo-panel> |
|||
</component> |
|||
<component name="ToolWindowManager"> |
|||
<frame x="0" y="41" width="3840" height="2119" extended-state="6" /> |
|||
<editor active="true" /> |
|||
<layout> |
|||
<window_info content_ui="combo" id="Project" order="0" sideWeight="0.5998948" visible="true" weight="0.109684326" /> |
|||
<window_info active="true" id="Structure" order="1" sideWeight="0.40010515" side_tool="true" visible="true" weight="0.109684326" /> |
|||
<window_info id="Favorites" order="2" side_tool="true" /> |
|||
<window_info anchor="bottom" id="GraphQL" /> |
|||
<window_info anchor="bottom" id="Message" order="0" /> |
|||
<window_info anchor="bottom" id="Find" order="1" /> |
|||
<window_info anchor="bottom" id="Run" order="2" weight="0.32993016" /> |
|||
<window_info anchor="bottom" id="Debug" order="3" weight="0.4" /> |
|||
<window_info anchor="bottom" id="Cvs" order="4" weight="0.25" /> |
|||
<window_info anchor="bottom" id="Inspection" order="5" weight="0.4" /> |
|||
<window_info anchor="bottom" id="TODO" order="6" weight="0.32993016" /> |
|||
<window_info anchor="bottom" id="Docker" order="7" show_stripe_button="false" /> |
|||
<window_info anchor="bottom" id="Database Changes" order="8" /> |
|||
<window_info anchor="bottom" id="Version Control" order="9" /> |
|||
<window_info anchor="bottom" id="Terminal" order="10" /> |
|||
<window_info anchor="bottom" id="Event Log" order="11" side_tool="true" weight="0.32993016" /> |
|||
<window_info anchor="right" id="Commander" internal_type="SLIDING" order="0" type="SLIDING" weight="0.4" /> |
|||
<window_info anchor="right" id="Ant Build" order="1" weight="0.25" /> |
|||
<window_info anchor="right" content_ui="combo" id="Hierarchy" order="2" weight="0.25" /> |
|||
<window_info anchor="right" id="Database" order="3" /> |
|||
</layout> |
|||
</component> |
|||
<component name="TypeScriptGeneratedFilesManager"> |
|||
<option name="version" value="1" /> |
|||
</component> |
|||
<component name="VgoProject"> |
|||
<integration-enabled>true</integration-enabled> |
|||
</component> |
|||
<component name="editorHistoryManager"> |
|||
<entry file="file://$PROJECT_DIR$/internal/store/space.go"> |
|||
<provider selected="true" editor-type-id="text-editor" /> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/database/mongodb/tags.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="1200"> |
|||
<caret line="34" column="27" selection-start-line="34" selection-start-column="27" selection-end-line="34" selection-end-column="27" /> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/repositories/tag.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="288"> |
|||
<caret line="10" column="49" selection-start-line="10" selection-start-column="42" selection-end-line="10" selection-end-column="49" /> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/.vscode/settings.json"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="144"> |
|||
<caret line="3" selection-start-line="3" selection-end-line="3" /> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/models/characters/list.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="-1095" /> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$USER_HOME$/go/pkg/mod/github.com/globalsign/mgo@v0.0.0-20180403085842-f76e4f9da92e/bulk.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="1608"> |
|||
<caret line="353" column="22" selection-start-line="353" selection-start-column="22" selection-end-line="353" selection-end-column="22" /> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/internal/store/db.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="-972" /> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/models/logs/find.go"> |
|||
<provider selected="true" editor-type-id="text-editor" /> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/models/logs/list.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="-432" /> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/models/logs/add.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="336"> |
|||
<caret line="7" column="22" selection-start-line="7" selection-start-column="22" selection-end-line="7" selection-end-column="22" /> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/internal/counter/counter.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="1305"> |
|||
<caret line="52" column="27" selection-start-line="52" selection-start-column="27" selection-end-line="52" selection-end-column="40" /> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/models/posts/remove.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="1056"> |
|||
<caret line="26" column="1" lean-forward="true" selection-start-line="26" selection-start-column="1" selection-end-line="26" selection-end-column="1" /> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/repositories/repository.go"> |
|||
<provider selected="true" editor-type-id="text-editor" /> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/models/characters/db.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="441"> |
|||
<caret line="34" selection-start-line="34" selection-end-line="52" selection-end-column="9" /> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/graph2/graphcore/input_gen.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="288"> |
|||
<caret line="6" selection-start-line="6" selection-end-line="6" /> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/graph2/schema/types/Character.gql"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="192"> |
|||
<caret line="4" lean-forward="true" selection-start-line="4" selection-end-line="4" /> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/tools.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="336"> |
|||
<caret line="7" selection-start-line="7" selection-end-line="7" /> |
|||
<folding> |
|||
<element signature="e#30#74#0" expanded="true" /> |
|||
</folding> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/go.mod"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="480"> |
|||
<caret line="10" column="22" selection-start-line="10" selection-start-column="22" selection-end-line="10" selection-end-column="22" /> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/database/database.go"> |
|||
<provider selected="true" editor-type-id="text-editor" /> |
|||
</entry> |
|||
<entry file="file://$USER_HOME$/go/pkg/mod/github.com/globalsign/mgo@v0.0.0-20180403085842-f76e4f9da92e/bson/bson.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="582"> |
|||
<caret line="154" column="5" selection-start-line="154" selection-start-column="5" selection-end-line="154" selection-end-column="6" /> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/.drone.yml"> |
|||
<provider selected="true" editor-type-id="text-editor" /> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/graph2/gqlgen.yml"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="755"> |
|||
<caret line="23" column="10" lean-forward="true" selection-start-line="23" selection-start-column="10" selection-end-line="23" selection-end-column="10" /> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/graph2/resolvers/resolvers.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="336"> |
|||
<caret line="10" lean-forward="true" selection-start-line="10" selection-end-line="10" /> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/database/mongodb/db.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="803"> |
|||
<caret line="81" column="30" selection-start-line="81" selection-start-column="30" selection-end-line="81" selection-end-column="30" /> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/services/tags.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="720"> |
|||
<caret line="15" column="71" selection-start-line="15" selection-start-column="71" selection-end-line="15" selection-end-column="71" /> |
|||
<folding> |
|||
<element signature="e#18#118#0" expanded="true" /> |
|||
</folding> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/graph2/complexity.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="624"> |
|||
<caret line="13" column="13" lean-forward="true" selection-start-line="13" selection-start-column="13" selection-end-line="13" selection-end-column="13" /> |
|||
<folding> |
|||
<element signature="e#16#377#0" expanded="true" /> |
|||
</folding> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/services/services.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="528"> |
|||
<caret line="11" column="1" lean-forward="true" selection-start-line="11" selection-start-column="1" selection-end-line="11" selection-end-column="1" /> |
|||
<folding> |
|||
<element signature="e#18#116#0" expanded="true" /> |
|||
</folding> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/graph2/graphcore/exec_gen.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="587"> |
|||
<caret line="1596" selection-start-line="1596" selection-end-line="1596" /> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/graph2/graph.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="1283"> |
|||
<caret line="37" column="11" lean-forward="true" selection-start-line="37" selection-start-column="11" selection-end-line="37" selection-end-column="11" /> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/graph2/types/log.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="515"> |
|||
<caret line="30" column="26" selection-start-line="30" selection-start-column="26" selection-end-line="30" selection-end-column="26" /> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/services/loaders/characterloader_gen.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="587"> |
|||
<caret line="115" column="26" selection-start-line="115" selection-start-column="26" selection-end-line="115" selection-end-column="26" /> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/graph2/resolvers/character.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="899"> |
|||
<caret line="29" column="12" lean-forward="true" selection-start-line="29" selection-start-column="12" selection-end-line="29" selection-end-column="12" /> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/services/loaders/loaders.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="288"> |
|||
<caret line="6" selection-start-line="6" selection-end-line="6" /> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/models/changekeys/many.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="816"> |
|||
<caret line="21" column="33" lean-forward="true" selection-start-line="21" selection-start-column="33" selection-end-line="21" selection-end-column="33" /> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/models/changekeys/listed.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="288"> |
|||
<caret line="6" column="14" selection-start-line="6" selection-start-column="14" selection-end-line="6" selection-end-column="14" /> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/models/changes/submit.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="723"> |
|||
<caret line="72" column="25" lean-forward="true" selection-start-line="72" selection-start-column="25" selection-end-line="72" selection-end-column="25" /> |
|||
<folding> |
|||
<element signature="e#17#136#0" expanded="true" /> |
|||
</folding> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$USER_HOME$/go/pkg/mod/github.com/globalsign/mgo@v0.0.0-20180403085842-f76e4f9da92e/session.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="539"> |
|||
<caret line="2707" column="14" selection-start-line="2707" selection-start-column="5" selection-end-line="2707" selection-end-column="14" /> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/models/token.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="1235"> |
|||
<caret line="41" selection-start-line="41" selection-end-line="41" /> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/internal/auth/permitted.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="816"> |
|||
<caret line="29" column="32" lean-forward="true" selection-start-line="29" selection-start-column="32" selection-end-line="29" selection-end-column="32" /> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/models/character.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="1043"> |
|||
<caret line="45" column="14" selection-start-line="45" selection-start-column="14" selection-end-line="45" selection-end-column="14" /> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/models/changekeys/one.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="851"> |
|||
<caret line="25" lean-forward="true" selection-start-line="25" selection-end-line="25" /> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/services/characters.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="1632"> |
|||
<caret line="63" column="25" lean-forward="true" selection-start-line="63" selection-start-column="25" selection-end-line="63" selection-end-column="25" /> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/repositories/character.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="576"> |
|||
<caret line="12" column="4" selection-start-line="12" selection-start-column="4" selection-end-line="12" selection-end-column="4" /> |
|||
<folding> |
|||
<element signature="e#22#80#0" expanded="true" /> |
|||
</folding> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
<entry file="file://$PROJECT_DIR$/database/mongodb/characters.go"> |
|||
<provider selected="true" editor-type-id="text-editor"> |
|||
<state relative-caret-position="419"> |
|||
<caret line="109" column="4" selection-start-line="109" selection-start-column="4" selection-end-line="109" selection-end-column="4" /> |
|||
</state> |
|||
</provider> |
|||
</entry> |
|||
</component> |
|||
</project> |
@ -0,0 +1,217 @@ |
|||
package mongodb |
|||
|
|||
import ( |
|||
"context" |
|||
"errors" |
|||
"github.com/globalsign/mgo" |
|||
"github.com/globalsign/mgo/bson" |
|||
"sort" |
|||
"strconv" |
|||
|
|||
"git.aiterp.net/rpdata/api/models" |
|||
"git.aiterp.net/rpdata/api/repositories" |
|||
) |
|||
|
|||
type characterRepository struct { |
|||
characters *mgo.Collection |
|||
cidCounter *counter |
|||
} |
|||
|
|||
func newCharacterRepository(db *mgo.Database) (repositories.CharacterRepository, error) { |
|||
collection := db.C("common.characters") |
|||
|
|||
err := collection.EnsureIndexKey("name") |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
err = collection.EnsureIndexKey("shortName") |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
err = collection.EnsureIndexKey("author") |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
err = collection.EnsureIndex(mgo.Index{ |
|||
Key: []string{"nicks"}, |
|||
Unique: true, |
|||
DropDups: true, |
|||
}) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
err = collection.EnsureIndex(mgo.Index{ |
|||
Key: []string{"$text:description"}, |
|||
}) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
return &characterRepository{ |
|||
characters: collection, |
|||
cidCounter: newCounter(db, "auto_increment", "Character"), |
|||
}, nil |
|||
} |
|||
|
|||
func (r *characterRepository) Find(ctx context.Context, id string) (*models.Character, error) { |
|||
character := new(models.Character) |
|||
err := r.characters.FindId(id).One(character) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
return character, nil |
|||
} |
|||
|
|||
func (r *characterRepository) FindNick(ctx context.Context, nick string) (*models.Character, error) { |
|||
character := new(models.Character) |
|||
err := r.characters.Find(bson.M{"nick": nick}).One(character) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
return character, nil |
|||
} |
|||
|
|||
func (r *characterRepository) List(ctx context.Context, filter models.CharacterFilter) ([]*models.Character, error) { |
|||
query := bson.M{} |
|||
if filter.Author != nil { |
|||
query["author"] = *filter.Author |
|||
} |
|||
if len(filter.IDs) > 0 { |
|||
query["_id"] = bson.M{"$in": filter.IDs} |
|||
} |
|||
if len(filter.Nicks) > 0 { |
|||
query["nicks"] = bson.M{"$in": filter.Nicks} |
|||
} |
|||
if len(filter.Names) > 0 { |
|||
query["$or"] = []bson.M{ |
|||
{"name": bson.M{"$in": filter.Names}}, |
|||
{"shortName": bson.M{"$in": filter.Names}}, |
|||
} |
|||
} |
|||
if filter.Search != nil { |
|||
query["$text"] = bson.M{"$search": *filter.Search} |
|||
} |
|||
|
|||
characters := make([]*models.Character, 0, 32) |
|||
err := r.characters.Find(query).All(&characters) |
|||
if err != nil { |
|||
if err == mgo.ErrNotFound { |
|||
return characters, nil |
|||
} |
|||
|
|||
return nil, err |
|||
} |
|||
|
|||
sort.Slice(characters, func(i, j int) bool { |
|||
ni, _ := strconv.Atoi(characters[i].ID[1:]) |
|||
nj, _ := strconv.Atoi(characters[j].ID[1:]) |
|||
|
|||
return ni < nj |
|||
}) |
|||
|
|||
return characters, nil |
|||
} |
|||
|
|||
func (r *characterRepository) Insert(ctx context.Context, character models.Character) (*models.Character, error) { |
|||
nextId, err := r.cidCounter.Increment(1) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
character.ID = "C" + strconv.Itoa(nextId) |
|||
|
|||
err = r.characters.Insert(&character) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
return &character, nil |
|||
} |
|||
|
|||
func (r *characterRepository) Update(ctx context.Context, character models.Character, update models.CharacterUpdate) (*models.Character, error) { |
|||
updateBson := bson.M{} |
|||
if update.Name != nil { |
|||
updateBson["name"] = *update.Name |
|||
character.Name = *update.Name |
|||
} |
|||
if update.ShortName != nil { |
|||
updateBson["shortName"] = *update.ShortName |
|||
character.ShortName = *update.ShortName |
|||
} |
|||
if update.Description != nil { |
|||
updateBson["description"] = *update.Description |
|||
character.Description = *update.Description |
|||
} |
|||
|
|||
err := r.characters.UpdateId(character.ID, bson.M{"$set": updateBson}) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
return &character, nil |
|||
} |
|||
|
|||
func (r *characterRepository) AddNick(ctx context.Context, character models.Character, nick string) (*models.Character, error) { |
|||
if character.HasNick(nick) { |
|||
return nil, errors.New("nick already exist") |
|||
} |
|||
|
|||
match := bson.M{ |
|||
"_id": character.ID, |
|||
"nicks": bson.M{"$ne": nick}, |
|||
} |
|||
|
|||
err := r.characters.Update(match, bson.M{"$push": bson.M{"nicks": nick}}) |
|||
if err == mgo.ErrNotFound { |
|||
return nil, repositories.ErrNotFound |
|||
} else if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
newNicks := make([]string, len(character.Nicks), len(character.Nicks)+1) |
|||
copy(newNicks, character.Nicks) |
|||
character.Nicks = append(newNicks, nick) |
|||
|
|||
return &character, nil |
|||
} |
|||
|
|||
func (r *characterRepository) RemoveNick(ctx context.Context, character models.Character, nick string) (*models.Character, error) { |
|||
if !character.HasNick(nick) { |
|||
return nil, errors.New("nick does not exist") |
|||
} |
|||
|
|||
match := bson.M{ |
|||
"_id": character.ID, |
|||
"nicks": nick, |
|||
} |
|||
|
|||
err := r.characters.Update(match, bson.M{"$pull": bson.M{"nicks": nick}}) |
|||
if err == mgo.ErrNotFound { |
|||
return nil, repositories.ErrNotFound |
|||
} else if mErr, ok := err.(*mgo.LastError); ok && mErr.Code == 11000 { |
|||
return nil, errors.New("The nick belongs to another character already") |
|||
} else if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
newNicks := make([]string, len(character.Nicks), len(character.Nicks)+1) |
|||
copy(newNicks, character.Nicks) |
|||
for i := range newNicks { |
|||
if newNicks[i] == nick { |
|||
newNicks = append(newNicks[:i], newNicks[i+1:]...) |
|||
break |
|||
} |
|||
} |
|||
character.Nicks = newNicks |
|||
|
|||
return &character, nil |
|||
} |
|||
|
|||
func (r *characterRepository) Delete(ctx context.Context, character models.Character) error { |
|||
return r.characters.RemoveId(character.ID) |
|||
} |
@ -1,14 +0,0 @@ |
|||
package tags |
|||
|
|||
import ( |
|||
"git.aiterp.net/rpdata/api/internal/store" |
|||
"github.com/globalsign/mgo" |
|||
) |
|||
|
|||
var storyCollection *mgo.Collection |
|||
|
|||
func init() { |
|||
store.HandleInit(func(db *mgo.Database) { |
|||
storyCollection = db.C("story.stories") |
|||
}) |
|||
} |
@ -1,26 +0,0 @@ |
|||
package tags |
|||
|
|||
import ( |
|||
"sort" |
|||
"strings" |
|||
|
|||
"git.aiterp.net/rpdata/api/models" |
|||
"github.com/globalsign/mgo/bson" |
|||
) |
|||
|
|||
// List lists all tags
|
|||
func List() ([]models.Tag, error) { |
|||
tags := make([]models.Tag, 0, 64) |
|||
err := storyCollection.Find(bson.M{"listed": true, "tags": bson.M{"$ne": nil}}).Distinct("tags", &tags) |
|||
|
|||
sort.Slice(tags, func(i, j int) bool { |
|||
kindCmp := strings.Compare(string(tags[i].Kind), string(tags[j].Kind)) |
|||
if kindCmp != 0 { |
|||
return kindCmp < 0 |
|||
} |
|||
|
|||
return strings.Compare(tags[i].Name, tags[j].Name) < 0 |
|||
}) |
|||
|
|||
return tags, err |
|||
} |
@ -0,0 +1,19 @@ |
|||
package repositories |
|||
|
|||
import ( |
|||
"context" |
|||
|
|||
"git.aiterp.net/rpdata/api/models" |
|||
) |
|||
|
|||
// CharacterRepository is an interface for a database using logs.
|
|||
type CharacterRepository interface { |
|||
Find(ctx context.Context, id string) (*models.Character, error) |
|||
FindNick(ctx context.Context, nick string) (*models.Character, error) |
|||
List(ctx context.Context, filter models.CharacterFilter) ([]*models.Character, error) |
|||
Insert(ctx context.Context, character models.Character) (*models.Character, error) |
|||
Update(ctx context.Context, character models.Character, update models.CharacterUpdate) (*models.Character, error) |
|||
AddNick(ctx context.Context, character models.Character, nick string) (*models.Character, error) |
|||
RemoveNick(ctx context.Context, character models.Character, nick string) (*models.Character, error) |
|||
Delete(ctx context.Context, character models.Character) error |
|||
} |
@ -0,0 +1,207 @@ |
|||
package services |
|||
|
|||
import ( |
|||
"context" |
|||
"errors" |
|||
"git.aiterp.net/rpdata/api/internal/auth" |
|||
"git.aiterp.net/rpdata/api/models" |
|||
"git.aiterp.net/rpdata/api/models/changekeys" |
|||
"git.aiterp.net/rpdata/api/models/changes" |
|||
"git.aiterp.net/rpdata/api/repositories" |
|||
"git.aiterp.net/rpdata/api/services/loaders" |
|||
"sort" |
|||
"strings" |
|||
) |
|||
|
|||
type CharacterService struct { |
|||
characters repositories.CharacterRepository |
|||
loader *loaders.CharacterLoader |
|||
} |
|||
|
|||
// Find uses the loader to find the character by the ID.
|
|||
func (s *CharacterService) Find(ctx context.Context, id string) (*models.Character, error) { |
|||
return s.loader.Load(id) |
|||
} |
|||
|
|||
// Find uses the loader to find the character by the ID.
|
|||
func (s *CharacterService) FindNick(ctx context.Context, nick string) (*models.Character, error) { |
|||
return s.characters.FindNick(ctx, nick) |
|||
} |
|||
|
|||
// List lists the characters. If the only filter active is `IDs`, the loader is used to batch together requests.
|
|||
func (s *CharacterService) List(ctx context.Context, filter models.CharacterFilter) ([]*models.Character, error) { |
|||
if len(filter.IDs) > 0 && len(filter.Names) == 0 && len(filter.Nicks) == 0 && filter.Author == nil && filter.Search == nil { |
|||
characters, errs := s.loader.LoadAll(filter.IDs) |
|||
if len(characters) == 0 && len(errs) > 0 { |
|||
if errs[0] == repositories.ErrNotFound { |
|||
return []*models.Character{}, nil |
|||
} else { |
|||
return nil, errs[0] |
|||
} |
|||
} |
|||
|
|||
if err := ctx.Err(); err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
var badIndices []int |
|||
for i, character := range characters { |
|||
if character == nil { |
|||
badIndices = append(badIndices, i-len(badIndices)) |
|||
} |
|||
} |
|||
for _, index := range badIndices { |
|||
characters = append(characters[:index], characters[index+1:]...) |
|||
} |
|||
|
|||
sort.Slice(characters, func(i, j int) bool { |
|||
return strings.Compare(characters[i].ID, characters[j].ID) < 0 |
|||
}) |
|||
|
|||
return characters, nil |
|||
} |
|||
|
|||
return s.characters.List(ctx, filter) |
|||
} |
|||
|
|||
func (s *CharacterService) Create(ctx context.Context, nick, name, shortName, author, description string) (*models.Character, error) { |
|||
token := auth.TokenFromContext(ctx) |
|||
if token == nil { |
|||
return nil, auth.ErrUnauthenticated |
|||
} |
|||
|
|||
if name == "" { |
|||
return nil, errors.New("Name cannot be empty") |
|||
} |
|||
|
|||
if author == "" { |
|||
author = token.UserID |
|||
} |
|||
|
|||
if shortName == "" { |
|||
split := strings.SplitN(name, " ", 2) |
|||
shortName = split[0] |
|||
} |
|||
|
|||
character := &models.Character{ |
|||
Name: name, |
|||
ShortName: shortName, |
|||
Author: author, |
|||
Nicks: []string{nick}, |
|||
Description: description, |
|||
} |
|||
|
|||
err := auth.CheckPermission(ctx, "add", character) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
character, err = s.characters.Insert(ctx, *character) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
//TODO: New change submit system
|
|||
go changes.Submit("Character", "add", token.UserID, true, changekeys.Listed(character), character) |
|||
|
|||
return character, nil |
|||
} |
|||
|
|||
func (s *CharacterService) Update(ctx context.Context, id string, name, shortName, description *string) (*models.Character, error) { |
|||
character, err := s.characters.Find(ctx, id) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
err = auth.CheckPermission(ctx, "edit", character) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
character, err = s.characters.Update(ctx, *character, models.CharacterUpdate{ |
|||
Name: name, |
|||
ShortName: shortName, |
|||
Description: description, |
|||
}) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
s.loader.Clear(character.ID) |
|||
s.loader.Prime(character.ID, character) |
|||
|
|||
//TODO: New change submit system
|
|||
token := auth.TokenFromContext(ctx) |
|||
go changes.Submit("Character", "edit", token.UserID, true, changekeys.Listed(character), character) |
|||
|
|||
return character, nil |
|||
} |
|||
|
|||
func (s *CharacterService) AddNick(ctx context.Context, id string, nick string) (*models.Character, error) { |
|||
character, err := s.characters.Find(ctx, id) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
err = auth.CheckPermission(ctx, "edit", character) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
character, err = s.characters.AddNick(ctx, *character, nick) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
//TODO: New change submit system
|
|||
token := auth.TokenFromContext(ctx) |
|||
go changes.Submit("Character", "edit", token.UserID, true, changekeys.Listed(character), character) |
|||
|
|||
return character, nil |
|||
} |
|||
|
|||
func (s *CharacterService) RemoveNick(ctx context.Context, id string, nick string) (*models.Character, error) { |
|||
character, err := s.characters.Find(ctx, id) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
err = auth.CheckPermission(ctx, "edit", character) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
character, err = s.characters.RemoveNick(ctx, *character, nick) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
//TODO: New change submit system
|
|||
token := auth.TokenFromContext(ctx) |
|||
go changes.Submit("Character", "edit", token.UserID, true, changekeys.Listed(character), character) |
|||
|
|||
return character, nil |
|||
} |
|||
|
|||
func (s *CharacterService) Delete(ctx context.Context, id string) (*models.Character, error) { |
|||
character, err := s.characters.Find(ctx, id) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
err = auth.CheckPermission(ctx, "edit", character) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
err = s.characters.Delete(ctx, *character) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
//TODO: New change submit system
|
|||
token := auth.TokenFromContext(ctx) |
|||
go changes.Submit("Character", "remove", token.UserID, true, changekeys.Listed(character), character) |
|||
|
|||
return character, nil |
|||
} |
@ -0,0 +1,224 @@ |
|||
// Code generated by github.com/vektah/dataloaden, DO NOT EDIT.
|
|||
|
|||
package loaders |
|||
|
|||
import ( |
|||
"sync" |
|||
"time" |
|||
|
|||
"git.aiterp.net/rpdata/api/models" |
|||
) |
|||
|
|||
// CharacterLoaderConfig captures the config to create a new CharacterLoader
|
|||
type CharacterLoaderConfig struct { |
|||
// Fetch is a method that provides the data for the loader
|
|||
Fetch func(keys []string) ([]*models.Character, []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 |
|||
} |
|||
|
|||
// NewCharacterLoader creates a new CharacterLoader given a fetch, wait, and maxBatch
|
|||
func NewCharacterLoader(config CharacterLoaderConfig) *CharacterLoader { |
|||
return &CharacterLoader{ |
|||
fetch: config.Fetch, |
|||
wait: config.Wait, |
|||
maxBatch: config.MaxBatch, |
|||
} |
|||
} |
|||
|
|||
// CharacterLoader batches and caches requests
|
|||
type CharacterLoader struct { |
|||
// this method provides the data for the loader
|
|||
fetch func(keys []string) ([]*models.Character, []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[string]*models.Character |
|||
|
|||
// 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 *characterLoaderBatch |
|||
|
|||
// mutex to prevent races
|
|||
mu sync.Mutex |
|||
} |
|||
|
|||
type characterLoaderBatch struct { |
|||
keys []string |
|||
data []*models.Character |
|||
error []error |
|||
closing bool |
|||
done chan struct{} |
|||
} |
|||
|
|||
// Load a Character by key, batching and caching will be applied automatically
|
|||
func (l *CharacterLoader) Load(key string) (*models.Character, error) { |
|||
return l.LoadThunk(key)() |
|||
} |
|||
|
|||
// LoadThunk returns a function that when called will block waiting for a Character.
|
|||
// 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 *CharacterLoader) LoadThunk(key string) func() (*models.Character, error) { |
|||
l.mu.Lock() |
|||
if it, ok := l.cache[key]; ok { |
|||
l.mu.Unlock() |
|||
return func() (*models.Character, error) { |
|||
return it, nil |
|||
} |
|||
} |
|||
if l.batch == nil { |
|||
l.batch = &characterLoaderBatch{done: make(chan struct{})} |
|||
} |
|||
batch := l.batch |
|||
pos := batch.keyIndex(l, key) |
|||
l.mu.Unlock() |
|||
|
|||
return func() (*models.Character, error) { |
|||
<-batch.done |
|||
|
|||
var data *models.Character |
|||
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 *CharacterLoader) LoadAll(keys []string) ([]*models.Character, []error) { |
|||
results := make([]func() (*models.Character, error), len(keys)) |
|||
|
|||
for i, key := range keys { |
|||
results[i] = l.LoadThunk(key) |
|||
} |
|||
|
|||
characters := make([]*models.Character, len(keys)) |
|||
errors := make([]error, len(keys)) |
|||
for i, thunk := range results { |
|||
characters[i], errors[i] = thunk() |
|||
} |
|||
return characters, errors |
|||
} |
|||
|
|||
// LoadAllThunk returns a function that when called will block waiting for a Characters.
|
|||
// 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 *CharacterLoader) LoadAllThunk(keys []string) func() ([]*models.Character, []error) { |
|||
results := make([]func() (*models.Character, error), len(keys)) |
|||
for i, key := range keys { |
|||
results[i] = l.LoadThunk(key) |
|||
} |
|||
return func() ([]*models.Character, []error) { |
|||
characters := make([]*models.Character, len(keys)) |
|||
errors := make([]error, len(keys)) |
|||
for i, thunk := range results { |
|||
characters[i], errors[i] = thunk() |
|||
} |
|||
return characters, 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 *CharacterLoader) Prime(key string, value *models.Character) 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 *CharacterLoader) Clear(key string) { |
|||
l.mu.Lock() |
|||
delete(l.cache, key) |
|||
l.mu.Unlock() |
|||
} |
|||
|
|||
func (l *CharacterLoader) unsafeSet(key string, value *models.Character) { |
|||
if l.cache == nil { |
|||
l.cache = map[string]*models.Character{} |
|||
} |
|||
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 *characterLoaderBatch) keyIndex(l *CharacterLoader, key string) 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 *characterLoaderBatch) startTimer(l *CharacterLoader) { |
|||
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 *characterLoaderBatch) end(l *CharacterLoader) { |
|||
b.data, b.error = l.fetch(b.keys) |
|||
close(b.done) |
|||
} |
@ -0,0 +1,53 @@ |
|||
package loaders |
|||
|
|||
import ( |
|||
"context" |
|||
"git.aiterp.net/rpdata/api/models" |
|||
"git.aiterp.net/rpdata/api/repositories" |
|||
"time" |
|||
) |
|||
|
|||
//go:generate go run github.com/vektah/dataloaden CharacterLoader string *git.aiterp.net/rpdata/api/models.Character
|
|||
|
|||
// CharacterLoaderFromRepository creates a new CharacterLoader
|
|||
func CharacterLoaderFromRepository(repo repositories.CharacterRepository) *CharacterLoader { |
|||
return &CharacterLoader{ |
|||
wait: time.Millisecond * 1, |
|||
maxBatch: 100, |
|||
fetch: func(keys []string) ([]*models.Character, []error) { |
|||
timeout, cancel := context.WithTimeout(context.Background(), time.Second*15) |
|||
defer cancel() |
|||
|
|||
characters, err := repo.List(timeout, models.CharacterFilter{ |
|||
IDs: keys, |
|||
}) |
|||
if err != nil { |
|||
errs := make([]error, len(keys)) |
|||
for i := range errs { |
|||
errs[i] = err |
|||
} |
|||
|
|||
return nil, errs |
|||
} |
|||
|
|||
charMap := make(map[string]*models.Character, len(keys)) |
|||
|
|||
for _, character := range characters { |
|||
charMap[character.ID] = character |
|||
} |
|||
|
|||
results := make([]*models.Character, len(keys)) |
|||
errs := make([]error, len(keys)) |
|||
|
|||
for i, key := range keys { |
|||
if character, ok := charMap[key]; ok { |
|||
results[i] = character |
|||
} else { |
|||
errs[i] = repositories.ErrNotFound |
|||
} |
|||
} |
|||
|
|||
return results, errs |
|||
}, |
|||
} |
|||
} |
@ -0,0 +1,7 @@ |
|||
//+build tools
|
|||
|
|||
package main |
|||
|
|||
import ( |
|||
_ "github.com/vektah/dataloaden" |
|||
) |
Write
Preview
Loading…
Cancel
Save
Reference in new issue