diff --git a/.vscode/settings.json b/.vscode/settings.json index 87392e61..21b1151e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,9 +1,6 @@ { "editor.formatOnSave": true, "go.lintTool": "golangci-lint", - "go.lintFlags": [ - "--fast" - ], "yaml.format.enable": true, "yaml.completion": true, "yaml.validate": true, diff --git a/Makefile b/Makefile index c27e1a73..6fb6cdeb 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ gen: go generate ./... gen/gql: - go generate ./internal/graphql + go generate ./internal/adapter/gql gen/builtin: go generate ./pkg/builtin diff --git a/internal/adapter/gql/generated.go b/internal/adapter/gql/generated.go index 869bd492..1972bd81 100644 --- a/internal/adapter/gql/generated.go +++ b/internal/adapter/gql/generated.go @@ -50,6 +50,8 @@ type ResolverRoot interface { InfoboxField() InfoboxFieldResolver LayerGroup() LayerGroupResolver LayerItem() LayerItemResolver + LayerTagGroup() LayerTagGroupResolver + LayerTagItem() LayerTagItemResolver MergedInfobox() MergedInfoboxResolver MergedInfoboxField() MergedInfoboxFieldResolver MergedLayer() MergedLayerResolver @@ -73,6 +75,7 @@ type ResolverRoot interface { Scene() SceneResolver ScenePlugin() ScenePluginResolver SceneWidget() SceneWidgetResolver + TagGroup() TagGroupResolver TagItem() TagItemResolver Team() TeamResolver TeamMember() TeamMemberResolver @@ -191,7 +194,8 @@ type ComplexityRoot struct { } CreateTagItemPayload struct { - Tag func(childComplexity int) int + Parent func(childComplexity int) int + Tag func(childComplexity int) int } CreateTeamPayload struct { @@ -364,7 +368,6 @@ type ComplexityRoot struct { Scene func(childComplexity int) int SceneID func(childComplexity int) int ScenePlugin func(childComplexity int) int - TagIds func(childComplexity int) int Tags func(childComplexity int) int } @@ -387,10 +390,20 @@ type ComplexityRoot struct { Scene func(childComplexity int) int SceneID func(childComplexity int) int ScenePlugin func(childComplexity int) int - TagIds func(childComplexity int) int Tags func(childComplexity int) int } + LayerTagGroup struct { + Children func(childComplexity int) int + Tag func(childComplexity int) int + TagID func(childComplexity int) int + } + + LayerTagItem struct { + Tag func(childComplexity int) int + TagID func(childComplexity int) int + } + MergedInfobox struct { Fields func(childComplexity int) int Property func(childComplexity int) int @@ -825,7 +838,8 @@ type ComplexityRoot struct { } RemoveTagPayload struct { - TagID func(childComplexity int) int + TagID func(childComplexity int) int + UpdatedLayers func(childComplexity int) int } RemoveWidgetPayload struct { @@ -896,19 +910,25 @@ type ComplexityRoot struct { TagGroup struct { ID func(childComplexity int) int Label func(childComplexity int) int + Layers func(childComplexity int) int + Scene func(childComplexity int) int SceneID func(childComplexity int) int + TagIds func(childComplexity int) int Tags func(childComplexity int) int } TagItem struct { ID func(childComplexity int) int Label func(childComplexity int) int + Layers func(childComplexity int) int LinkedDataset func(childComplexity int) int LinkedDatasetField func(childComplexity int) int LinkedDatasetFieldID func(childComplexity int) int LinkedDatasetID func(childComplexity int) int LinkedDatasetSchema func(childComplexity int) int LinkedDatasetSchemaID func(childComplexity int) int + Parent func(childComplexity int) int + ParentID func(childComplexity int) int SceneID func(childComplexity int) int } @@ -1093,8 +1113,6 @@ type LayerGroupResolver interface { Layers(ctx context.Context, obj *gqlmodel.LayerGroup) ([]gqlmodel.Layer, error) Scene(ctx context.Context, obj *gqlmodel.LayerGroup) (*gqlmodel.Scene, error) ScenePlugin(ctx context.Context, obj *gqlmodel.LayerGroup) (*gqlmodel.ScenePlugin, error) - - Tags(ctx context.Context, obj *gqlmodel.LayerGroup) ([]gqlmodel.Tag, error) } type LayerItemResolver interface { Parent(ctx context.Context, obj *gqlmodel.LayerItem) (*gqlmodel.LayerGroup, error) @@ -1105,8 +1123,12 @@ type LayerItemResolver interface { Merged(ctx context.Context, obj *gqlmodel.LayerItem) (*gqlmodel.MergedLayer, error) Scene(ctx context.Context, obj *gqlmodel.LayerItem) (*gqlmodel.Scene, error) ScenePlugin(ctx context.Context, obj *gqlmodel.LayerItem) (*gqlmodel.ScenePlugin, error) - - Tags(ctx context.Context, obj *gqlmodel.LayerItem) ([]gqlmodel.Tag, error) +} +type LayerTagGroupResolver interface { + Tag(ctx context.Context, obj *gqlmodel.LayerTagGroup) (gqlmodel.Tag, error) +} +type LayerTagItemResolver interface { + Tag(ctx context.Context, obj *gqlmodel.LayerTagItem) (gqlmodel.Tag, error) } type MergedInfoboxResolver interface { Scene(ctx context.Context, obj *gqlmodel.MergedInfobox) (*gqlmodel.Scene, error) @@ -1305,10 +1327,17 @@ type SceneWidgetResolver interface { Extension(ctx context.Context, obj *gqlmodel.SceneWidget) (*gqlmodel.PluginExtension, error) Property(ctx context.Context, obj *gqlmodel.SceneWidget) (*gqlmodel.Property, error) } +type TagGroupResolver interface { + Tags(ctx context.Context, obj *gqlmodel.TagGroup) ([]*gqlmodel.TagItem, error) + Scene(ctx context.Context, obj *gqlmodel.TagGroup) (*gqlmodel.Scene, error) + Layers(ctx context.Context, obj *gqlmodel.TagGroup) ([]gqlmodel.Layer, error) +} type TagItemResolver interface { LinkedDatasetSchema(ctx context.Context, obj *gqlmodel.TagItem) (*gqlmodel.DatasetSchema, error) LinkedDataset(ctx context.Context, obj *gqlmodel.TagItem) (*gqlmodel.Dataset, error) LinkedDatasetField(ctx context.Context, obj *gqlmodel.TagItem) (*gqlmodel.DatasetField, error) + Parent(ctx context.Context, obj *gqlmodel.TagItem) (*gqlmodel.TagGroup, error) + Layers(ctx context.Context, obj *gqlmodel.TagItem) ([]gqlmodel.Layer, error) } type TeamResolver interface { Assets(ctx context.Context, obj *gqlmodel.Team, first *int, last *int, after *usecase.Cursor, before *usecase.Cursor) (*gqlmodel.AssetConnection, error) @@ -1666,6 +1695,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.CreateTagGroupPayload.Tag(childComplexity), true + case "CreateTagItemPayload.parent": + if e.complexity.CreateTagItemPayload.Parent == nil { + break + } + + return e.complexity.CreateTagItemPayload.Parent(childComplexity), true + case "CreateTagItemPayload.tag": if e.complexity.CreateTagItemPayload.Tag == nil { break @@ -2420,13 +2456,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.LayerGroup.ScenePlugin(childComplexity), true - case "LayerGroup.tagIds": - if e.complexity.LayerGroup.TagIds == nil { - break - } - - return e.complexity.LayerGroup.TagIds(childComplexity), true - case "LayerGroup.tags": if e.complexity.LayerGroup.Tags == nil { break @@ -2560,19 +2589,47 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.LayerItem.ScenePlugin(childComplexity), true - case "LayerItem.tagIds": - if e.complexity.LayerItem.TagIds == nil { + case "LayerItem.tags": + if e.complexity.LayerItem.Tags == nil { break } - return e.complexity.LayerItem.TagIds(childComplexity), true + return e.complexity.LayerItem.Tags(childComplexity), true - case "LayerItem.tags": - if e.complexity.LayerItem.Tags == nil { + case "LayerTagGroup.children": + if e.complexity.LayerTagGroup.Children == nil { break } - return e.complexity.LayerItem.Tags(childComplexity), true + return e.complexity.LayerTagGroup.Children(childComplexity), true + + case "LayerTagGroup.tag": + if e.complexity.LayerTagGroup.Tag == nil { + break + } + + return e.complexity.LayerTagGroup.Tag(childComplexity), true + + case "LayerTagGroup.tagId": + if e.complexity.LayerTagGroup.TagID == nil { + break + } + + return e.complexity.LayerTagGroup.TagID(childComplexity), true + + case "LayerTagItem.tag": + if e.complexity.LayerTagItem.Tag == nil { + break + } + + return e.complexity.LayerTagItem.Tag(childComplexity), true + + case "LayerTagItem.tagId": + if e.complexity.LayerTagItem.TagID == nil { + break + } + + return e.complexity.LayerTagItem.TagID(childComplexity), true case "MergedInfobox.fields": if e.complexity.MergedInfobox.Fields == nil { @@ -5222,6 +5279,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.RemoveTagPayload.TagID(childComplexity), true + case "RemoveTagPayload.updatedLayers": + if e.complexity.RemoveTagPayload.UpdatedLayers == nil { + break + } + + return e.complexity.RemoveTagPayload.UpdatedLayers(childComplexity), true + case "RemoveWidgetPayload.scene": if e.complexity.RemoveWidgetPayload.Scene == nil { break @@ -5549,6 +5613,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.TagGroup.Label(childComplexity), true + case "TagGroup.layers": + if e.complexity.TagGroup.Layers == nil { + break + } + + return e.complexity.TagGroup.Layers(childComplexity), true + + case "TagGroup.scene": + if e.complexity.TagGroup.Scene == nil { + break + } + + return e.complexity.TagGroup.Scene(childComplexity), true + case "TagGroup.sceneId": if e.complexity.TagGroup.SceneID == nil { break @@ -5556,6 +5634,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.TagGroup.SceneID(childComplexity), true + case "TagGroup.tagIds": + if e.complexity.TagGroup.TagIds == nil { + break + } + + return e.complexity.TagGroup.TagIds(childComplexity), true + case "TagGroup.tags": if e.complexity.TagGroup.Tags == nil { break @@ -5577,6 +5662,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.TagItem.Label(childComplexity), true + case "TagItem.layers": + if e.complexity.TagItem.Layers == nil { + break + } + + return e.complexity.TagItem.Layers(childComplexity), true + case "TagItem.linkedDataset": if e.complexity.TagItem.LinkedDataset == nil { break @@ -5619,6 +5711,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.TagItem.LinkedDatasetSchemaID(childComplexity), true + case "TagItem.parent": + if e.complexity.TagItem.Parent == nil { + break + } + + return e.complexity.TagItem.Parent(childComplexity), true + + case "TagItem.parentId": + if e.complexity.TagItem.ParentID == nil { + break + } + + return e.complexity.TagItem.ParentID(childComplexity), true + case "TagItem.sceneId": if e.complexity.TagItem.SceneID == nil { break @@ -6461,7 +6567,6 @@ enum PluginExtensionType { INFOBOX } - type PluginExtension { extensionId: PluginExtensionID! pluginId: PluginID! @@ -6803,12 +6908,9 @@ interface Layer { plugin: Plugin extension: PluginExtension scenePlugin: ScenePlugin - tagIds: [ID!]! - tags: [Tag!]! @goField(forceResolver: true) + tags: [LayerTag!]! } -union Layers = LayerItem | LayerGroup - enum LayerEncodingFormat { KML CZML @@ -6829,6 +6931,7 @@ type LayerItem implements Layer { # parentId will not be always set parentId: ID linkedDatasetId: ID + tags: [LayerTag!]! parent: LayerGroup @goField(forceResolver: true) property: Property @goField(forceResolver: true) plugin: Plugin @goField(forceResolver: true) @@ -6837,8 +6940,6 @@ type LayerItem implements Layer { merged: MergedLayer @goField(forceResolver: true) scene: Scene @goField(forceResolver: true) scenePlugin: ScenePlugin @goField(forceResolver: true) - tagIds: [ID!]! - tags: [Tag!]! @goField(forceResolver: true) } type LayerGroup implements Layer { @@ -6855,6 +6956,7 @@ type LayerGroup implements Layer { linkedDatasetSchemaId: ID root: Boolean! layerIds: [ID!]! + tags: [LayerTag!]! parent: LayerGroup @goField(forceResolver: true) property: Property @goField(forceResolver: true) plugin: Plugin @goField(forceResolver: true) @@ -6863,8 +6965,6 @@ type LayerGroup implements Layer { layers: [Layer]! @goField(forceResolver: true) scene: Scene @goField(forceResolver: true) scenePlugin: ScenePlugin @goField(forceResolver: true) - tagIds: [ID!]! - tags: [Tag!]! @goField(forceResolver: true) } type Infobox { @@ -6899,6 +6999,22 @@ type InfoboxField { scenePlugin: ScenePlugin @goField(forceResolver: true) } +interface LayerTag { + tagId: ID! + tag: Tag +} + +type LayerTagItem implements LayerTag { + tagId: ID! + tag: Tag @goField(forceResolver: true) +} + +type LayerTagGroup implements LayerTag { + tagId: ID! + children: [LayerTagItem!]! + tag: Tag @goField(forceResolver: true) +} + type MergedLayer { originalId: ID! parentId: ID @@ -6933,29 +7049,34 @@ interface Tag { id: ID! sceneId: ID! label: String! + layers: [Layer!]! @goField(forceResolver: true) } type TagItem implements Tag { id: ID! sceneId: ID! label: String! + parentId: ID linkedDatasetID: ID linkedDatasetSchemaID: ID linkedDatasetFieldID: ID linkedDatasetSchema: DatasetSchema @goField(forceResolver: true) linkedDataset: Dataset @goField(forceResolver: true) linkedDatasetField: DatasetField @goField(forceResolver: true) + parent: TagGroup @goField(forceResolver: true) + layers: [Layer!]! @goField(forceResolver: true) } type TagGroup implements Tag { id: ID! sceneId: ID! label: String! - tags: [ID!] + tagIds: [ID!] + tags: [TagItem!]! @goField(forceResolver: true) + scene: Scene @goField(forceResolver: true) + layers: [Layer!]! @goField(forceResolver: true) } -union Tags = TagItem | TagGroup - type Cluster { id: ID! name: String! @@ -7319,6 +7440,7 @@ input AddDatasetSchemaInput { input CreateTagItemInput { sceneId: ID! label: String! + parent: ID linkedDatasetSchemaID: ID linkedDatasetID: ID linkedDatasetField: ID @@ -7578,6 +7700,7 @@ type AddDatasetSchemaPayload { type CreateTagItemPayload { tag: TagItem! + parent: TagGroup } type CreateTagGroupPayload { @@ -7596,16 +7719,17 @@ type UpdateTagPayload { tag: Tag! } -type AttachTagToLayerPayload{ +type AttachTagToLayerPayload { layer: Layer! } -type DetachTagFromLayerPayload{ +type DetachTagFromLayerPayload { layer: Layer! } -type RemoveTagPayload{ +type RemoveTagPayload { tagId: ID! + updatedLayers: [Layer!]! } type AddClusterPayload { @@ -7618,7 +7742,7 @@ type UpdateClusterPayload { cluster: Cluster! } -type RemoveClusterPayload{ +type RemoveClusterPayload { scene: Scene! clusterId: ID! } @@ -7754,7 +7878,9 @@ type Mutation { createScene(input: CreateSceneInput!): CreateScenePayload addWidget(input: AddWidgetInput!): AddWidgetPayload updateWidget(input: UpdateWidgetInput!): UpdateWidgetPayload - updateWidgetAlignSystem(input: UpdateWidgetAlignSystemInput!): UpdateWidgetAlignSystemPayload + updateWidgetAlignSystem( + input: UpdateWidgetAlignSystemInput! + ): UpdateWidgetAlignSystemPayload removeWidget(input: RemoveWidgetInput!): RemoveWidgetPayload installPlugin(input: InstallPluginInput!): InstallPluginPayload uninstallPlugin(input: UninstallPluginInput!): UninstallPluginPayload @@ -7777,7 +7903,9 @@ type Mutation { input: RemoveDatasetSchemaInput! ): RemoveDatasetSchemaPayload importDataset(input: ImportDatasetInput!): ImportDatasetPayload - importDatasetFromGoogleSheet(input: ImportDatasetFromGoogleSheetInput!): ImportDatasetPayload + importDatasetFromGoogleSheet( + input: ImportDatasetFromGoogleSheetInput! + ): ImportDatasetPayload addDatasetSchema(input: AddDatasetSchemaInput!): AddDatasetSchemaPayload # Property @@ -7811,8 +7939,12 @@ type Mutation { # Tag createTagItem(input: CreateTagItemInput!): CreateTagItemPayload createTagGroup(input: CreateTagGroupInput!): CreateTagGroupPayload - attachTagItemToGroup(input: AttachTagItemToGroupInput!): AttachTagItemToGroupPayload - detachTagItemFromGroup(input: DetachTagItemFromGroupInput!): DetachTagItemFromGroupPayload + attachTagItemToGroup( + input: AttachTagItemToGroupInput! + ): AttachTagItemToGroupPayload + detachTagItemFromGroup( + input: DetachTagItemFromGroupInput! + ): DetachTagItemFromGroupPayload updateTag(input: UpdateTagInput!): UpdateTagPayload removeTag(input: RemoveTagInput!): RemoveTagPayload } @@ -11236,6 +11368,38 @@ func (ec *executionContext) _CreateTagItemPayload_tag(ctx context.Context, field return ec.marshalNTagItem2ᚖgithubᚗcomᚋreearthᚋreearthᚑbackendᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐTagItem(ctx, field.Selections, res) } +func (ec *executionContext) _CreateTagItemPayload_parent(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.CreateTagItemPayload) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "CreateTagItemPayload", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Parent, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*gqlmodel.TagGroup) + fc.Result = res + return ec.marshalOTagGroup2ᚖgithubᚗcomᚋreearthᚋreearthᚑbackendᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐTagGroup(ctx, field.Selections, res) +} + func (ec *executionContext) _CreateTeamPayload_team(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.CreateTeamPayload) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -14571,6 +14735,41 @@ func (ec *executionContext) _LayerGroup_layerIds(ctx context.Context, field grap return ec.marshalNID2ᚕᚖgithubᚗcomᚋreearthᚋreearthᚑbackendᚋpkgᚋidᚐIDᚄ(ctx, field.Selections, res) } +func (ec *executionContext) _LayerGroup_tags(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.LayerGroup) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "LayerGroup", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Tags, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]gqlmodel.LayerTag) + fc.Result = res + return ec.marshalNLayerTag2ᚕgithubᚗcomᚋreearthᚋreearthᚑbackendᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐLayerTagᚄ(ctx, field.Selections, res) +} + func (ec *executionContext) _LayerGroup_parent(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.LayerGroup) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -14830,76 +15029,6 @@ func (ec *executionContext) _LayerGroup_scenePlugin(ctx context.Context, field g return ec.marshalOScenePlugin2ᚖgithubᚗcomᚋreearthᚋreearthᚑbackendᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐScenePlugin(ctx, field.Selections, res) } -func (ec *executionContext) _LayerGroup_tagIds(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.LayerGroup) (ret graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - fc := &graphql.FieldContext{ - Object: "LayerGroup", - Field: field, - Args: nil, - IsMethod: false, - IsResolver: false, - } - - ctx = graphql.WithFieldContext(ctx, fc) - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.TagIds, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.([]*id.ID) - fc.Result = res - return ec.marshalNID2ᚕᚖgithubᚗcomᚋreearthᚋreearthᚑbackendᚋpkgᚋidᚐIDᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) _LayerGroup_tags(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.LayerGroup) (ret graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - fc := &graphql.FieldContext{ - Object: "LayerGroup", - Field: field, - Args: nil, - IsMethod: true, - IsResolver: true, - } - - ctx = graphql.WithFieldContext(ctx, fc) - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.LayerGroup().Tags(rctx, obj) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.([]gqlmodel.Tag) - fc.Result = res - return ec.marshalNTag2ᚕgithubᚗcomᚋreearthᚋreearthᚑbackendᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐTagᚄ(ctx, field.Selections, res) -} - func (ec *executionContext) _LayerItem_id(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.LayerItem) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -15232,6 +15361,41 @@ func (ec *executionContext) _LayerItem_linkedDatasetId(ctx context.Context, fiel return ec.marshalOID2ᚖgithubᚗcomᚋreearthᚋreearthᚑbackendᚋpkgᚋidᚐID(ctx, field.Selections, res) } +func (ec *executionContext) _LayerItem_tags(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.LayerItem) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "LayerItem", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Tags, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]gqlmodel.LayerTag) + fc.Result = res + return ec.marshalNLayerTag2ᚕgithubᚗcomᚋreearthᚋreearthᚑbackendᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐLayerTagᚄ(ctx, field.Selections, res) +} + func (ec *executionContext) _LayerItem_parent(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.LayerItem) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -15488,7 +15652,7 @@ func (ec *executionContext) _LayerItem_scenePlugin(ctx context.Context, field gr return ec.marshalOScenePlugin2ᚖgithubᚗcomᚋreearthᚋreearthᚑbackendᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐScenePlugin(ctx, field.Selections, res) } -func (ec *executionContext) _LayerItem_tagIds(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.LayerItem) (ret graphql.Marshaler) { +func (ec *executionContext) _LayerTagGroup_tagId(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.LayerTagGroup) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -15496,7 +15660,7 @@ func (ec *executionContext) _LayerItem_tagIds(ctx context.Context, field graphql } }() fc := &graphql.FieldContext{ - Object: "LayerItem", + Object: "LayerTagGroup", Field: field, Args: nil, IsMethod: false, @@ -15506,7 +15670,7 @@ func (ec *executionContext) _LayerItem_tagIds(ctx context.Context, field graphql ctx = graphql.WithFieldContext(ctx, fc) resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.TagIds, nil + return obj.TagID, nil }) if err != nil { ec.Error(ctx, err) @@ -15518,12 +15682,12 @@ func (ec *executionContext) _LayerItem_tagIds(ctx context.Context, field graphql } return graphql.Null } - res := resTmp.([]*id.ID) + res := resTmp.(id.ID) fc.Result = res - return ec.marshalNID2ᚕᚖgithubᚗcomᚋreearthᚋreearthᚑbackendᚋpkgᚋidᚐIDᚄ(ctx, field.Selections, res) + return ec.marshalNID2githubᚗcomᚋreearthᚋreearthᚑbackendᚋpkgᚋidᚐID(ctx, field.Selections, res) } -func (ec *executionContext) _LayerItem_tags(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.LayerItem) (ret graphql.Marshaler) { +func (ec *executionContext) _LayerTagGroup_children(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.LayerTagGroup) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -15531,7 +15695,42 @@ func (ec *executionContext) _LayerItem_tags(ctx context.Context, field graphql.C } }() fc := &graphql.FieldContext{ - Object: "LayerItem", + Object: "LayerTagGroup", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Children, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]*gqlmodel.LayerTagItem) + fc.Result = res + return ec.marshalNLayerTagItem2ᚕᚖgithubᚗcomᚋreearthᚋreearthᚑbackendᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐLayerTagItemᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _LayerTagGroup_tag(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.LayerTagGroup) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "LayerTagGroup", Field: field, Args: nil, IsMethod: true, @@ -15541,7 +15740,39 @@ func (ec *executionContext) _LayerItem_tags(ctx context.Context, field graphql.C ctx = graphql.WithFieldContext(ctx, fc) resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.LayerItem().Tags(rctx, obj) + return ec.resolvers.LayerTagGroup().Tag(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(gqlmodel.Tag) + fc.Result = res + return ec.marshalOTag2githubᚗcomᚋreearthᚋreearthᚑbackendᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐTag(ctx, field.Selections, res) +} + +func (ec *executionContext) _LayerTagItem_tagId(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.LayerTagItem) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "LayerTagItem", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.TagID, nil }) if err != nil { ec.Error(ctx, err) @@ -15553,9 +15784,41 @@ func (ec *executionContext) _LayerItem_tags(ctx context.Context, field graphql.C } return graphql.Null } - res := resTmp.([]gqlmodel.Tag) + res := resTmp.(id.ID) fc.Result = res - return ec.marshalNTag2ᚕgithubᚗcomᚋreearthᚋreearthᚑbackendᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐTagᚄ(ctx, field.Selections, res) + return ec.marshalNID2githubᚗcomᚋreearthᚋreearthᚑbackendᚋpkgᚋidᚐID(ctx, field.Selections, res) +} + +func (ec *executionContext) _LayerTagItem_tag(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.LayerTagItem) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "LayerTagItem", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.LayerTagItem().Tag(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(gqlmodel.Tag) + fc.Result = res + return ec.marshalOTag2githubᚗcomᚋreearthᚋreearthᚑbackendᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐTag(ctx, field.Selections, res) } func (ec *executionContext) _MergedInfobox_sceneID(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.MergedInfobox) (ret graphql.Marshaler) { @@ -26721,6 +26984,41 @@ func (ec *executionContext) _RemoveTagPayload_tagId(ctx context.Context, field g return ec.marshalNID2githubᚗcomᚋreearthᚋreearthᚑbackendᚋpkgᚋidᚐID(ctx, field.Selections, res) } +func (ec *executionContext) _RemoveTagPayload_updatedLayers(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.RemoveTagPayload) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "RemoveTagPayload", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.UpdatedLayers, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]gqlmodel.Layer) + fc.Result = res + return ec.marshalNLayer2ᚕgithubᚗcomᚋreearthᚋreearthᚑbackendᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐLayerᚄ(ctx, field.Selections, res) +} + func (ec *executionContext) _RemoveWidgetPayload_scene(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.RemoveWidgetPayload) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -28340,7 +28638,7 @@ func (ec *executionContext) _TagGroup_label(ctx context.Context, field graphql.C return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) _TagGroup_tags(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.TagGroup) (ret graphql.Marshaler) { +func (ec *executionContext) _TagGroup_tagIds(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.TagGroup) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -28358,7 +28656,7 @@ func (ec *executionContext) _TagGroup_tags(ctx context.Context, field graphql.Co ctx = graphql.WithFieldContext(ctx, fc) resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.Tags, nil + return obj.TagIds, nil }) if err != nil { ec.Error(ctx, err) @@ -28372,6 +28670,108 @@ func (ec *executionContext) _TagGroup_tags(ctx context.Context, field graphql.Co return ec.marshalOID2ᚕᚖgithubᚗcomᚋreearthᚋreearthᚑbackendᚋpkgᚋidᚐIDᚄ(ctx, field.Selections, res) } +func (ec *executionContext) _TagGroup_tags(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.TagGroup) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "TagGroup", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.TagGroup().Tags(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]*gqlmodel.TagItem) + fc.Result = res + return ec.marshalNTagItem2ᚕᚖgithubᚗcomᚋreearthᚋreearthᚑbackendᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐTagItemᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _TagGroup_scene(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.TagGroup) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "TagGroup", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.TagGroup().Scene(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*gqlmodel.Scene) + fc.Result = res + return ec.marshalOScene2ᚖgithubᚗcomᚋreearthᚋreearthᚑbackendᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐScene(ctx, field.Selections, res) +} + +func (ec *executionContext) _TagGroup_layers(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.TagGroup) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "TagGroup", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.TagGroup().Layers(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]gqlmodel.Layer) + fc.Result = res + return ec.marshalNLayer2ᚕgithubᚗcomᚋreearthᚋreearthᚑbackendᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐLayerᚄ(ctx, field.Selections, res) +} + func (ec *executionContext) _TagItem_id(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.TagItem) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -28477,6 +28877,38 @@ func (ec *executionContext) _TagItem_label(ctx context.Context, field graphql.Co return ec.marshalNString2string(ctx, field.Selections, res) } +func (ec *executionContext) _TagItem_parentId(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.TagItem) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "TagItem", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ParentID, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*id.ID) + fc.Result = res + return ec.marshalOID2ᚖgithubᚗcomᚋreearthᚋreearthᚑbackendᚋpkgᚋidᚐID(ctx, field.Selections, res) +} + func (ec *executionContext) _TagItem_linkedDatasetID(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.TagItem) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -28669,6 +29101,73 @@ func (ec *executionContext) _TagItem_linkedDatasetField(ctx context.Context, fie return ec.marshalODatasetField2ᚖgithubᚗcomᚋreearthᚋreearthᚑbackendᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐDatasetField(ctx, field.Selections, res) } +func (ec *executionContext) _TagItem_parent(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.TagItem) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "TagItem", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.TagItem().Parent(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*gqlmodel.TagGroup) + fc.Result = res + return ec.marshalOTagGroup2ᚖgithubᚗcomᚋreearthᚋreearthᚑbackendᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐTagGroup(ctx, field.Selections, res) +} + +func (ec *executionContext) _TagItem_layers(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.TagItem) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "TagItem", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.TagItem().Layers(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]gqlmodel.Layer) + fc.Result = res + return ec.marshalNLayer2ᚕgithubᚗcomᚋreearthᚋreearthᚑbackendᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐLayerᚄ(ctx, field.Selections, res) +} + func (ec *executionContext) _Team_id(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.Team) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -32713,6 +33212,14 @@ func (ec *executionContext) unmarshalInputCreateTagItemInput(ctx context.Context if err != nil { return it, err } + case "parent": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("parent")) + it.Parent, err = ec.unmarshalOID2ᚖgithubᚗcomᚋreearthᚋreearthᚑbackendᚋpkgᚋidᚐID(ctx, v) + if err != nil { + return it, err + } case "linkedDatasetSchemaID": var err error @@ -34698,24 +35205,24 @@ func (ec *executionContext) _Layer(ctx context.Context, sel ast.SelectionSet, ob } } -func (ec *executionContext) _Layers(ctx context.Context, sel ast.SelectionSet, obj gqlmodel.Layers) graphql.Marshaler { +func (ec *executionContext) _LayerTag(ctx context.Context, sel ast.SelectionSet, obj gqlmodel.LayerTag) graphql.Marshaler { switch obj := (obj).(type) { case nil: return graphql.Null - case gqlmodel.LayerItem: - return ec._LayerItem(ctx, sel, &obj) - case *gqlmodel.LayerItem: + case gqlmodel.LayerTagItem: + return ec._LayerTagItem(ctx, sel, &obj) + case *gqlmodel.LayerTagItem: if obj == nil { return graphql.Null } - return ec._LayerItem(ctx, sel, obj) - case gqlmodel.LayerGroup: - return ec._LayerGroup(ctx, sel, &obj) - case *gqlmodel.LayerGroup: + return ec._LayerTagItem(ctx, sel, obj) + case gqlmodel.LayerTagGroup: + return ec._LayerTagGroup(ctx, sel, &obj) + case *gqlmodel.LayerTagGroup: if obj == nil { return graphql.Null } - return ec._LayerGroup(ctx, sel, obj) + return ec._LayerTagGroup(ctx, sel, obj) default: panic(fmt.Errorf("unexpected type %T", obj)) } @@ -34839,29 +35346,6 @@ func (ec *executionContext) _Tag(ctx context.Context, sel ast.SelectionSet, obj } } -func (ec *executionContext) _Tags(ctx context.Context, sel ast.SelectionSet, obj gqlmodel.Tags) graphql.Marshaler { - switch obj := (obj).(type) { - case nil: - return graphql.Null - case gqlmodel.TagItem: - return ec._TagItem(ctx, sel, &obj) - case *gqlmodel.TagItem: - if obj == nil { - return graphql.Null - } - return ec._TagItem(ctx, sel, obj) - case gqlmodel.TagGroup: - return ec._TagGroup(ctx, sel, &obj) - case *gqlmodel.TagGroup: - if obj == nil { - return graphql.Null - } - return ec._TagGroup(ctx, sel, obj) - default: - panic(fmt.Errorf("unexpected type %T", obj)) - } -} - // endregion ************************** interface.gotpl *************************** // region **************************** object.gotpl **************************** @@ -35542,6 +36026,8 @@ func (ec *executionContext) _CreateTagItemPayload(ctx context.Context, sel ast.S if out.Values[i] == graphql.Null { invalids++ } + case "parent": + out.Values[i] = ec._CreateTagItemPayload_parent(ctx, field, obj) default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -36577,7 +37063,7 @@ func (ec *executionContext) _LatLngHeight(ctx context.Context, sel ast.Selection return out } -var layerGroupImplementors = []string{"LayerGroup", "Layers", "Layer"} +var layerGroupImplementors = []string{"LayerGroup", "Layer"} func (ec *executionContext) _LayerGroup(ctx context.Context, sel ast.SelectionSet, obj *gqlmodel.LayerGroup) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, layerGroupImplementors) @@ -36630,6 +37116,11 @@ func (ec *executionContext) _LayerGroup(ctx context.Context, sel ast.SelectionSe if out.Values[i] == graphql.Null { atomic.AddUint32(&invalids, 1) } + case "tags": + out.Values[i] = ec._LayerGroup_tags(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } case "parent": field := field out.Concurrently(i, func() (res graphql.Marshaler) { @@ -36721,25 +37212,6 @@ func (ec *executionContext) _LayerGroup(ctx context.Context, sel ast.SelectionSe res = ec._LayerGroup_scenePlugin(ctx, field, obj) return res }) - case "tagIds": - out.Values[i] = ec._LayerGroup_tagIds(ctx, field, obj) - if out.Values[i] == graphql.Null { - atomic.AddUint32(&invalids, 1) - } - case "tags": - field := field - out.Concurrently(i, func() (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._LayerGroup_tags(ctx, field, obj) - if res == graphql.Null { - atomic.AddUint32(&invalids, 1) - } - return res - }) default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -36751,7 +37223,7 @@ func (ec *executionContext) _LayerGroup(ctx context.Context, sel ast.SelectionSe return out } -var layerItemImplementors = []string{"LayerItem", "Layers", "Layer"} +var layerItemImplementors = []string{"LayerItem", "Layer"} func (ec *executionContext) _LayerItem(ctx context.Context, sel ast.SelectionSet, obj *gqlmodel.LayerItem) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, layerItemImplementors) @@ -36794,6 +37266,11 @@ func (ec *executionContext) _LayerItem(ctx context.Context, sel ast.SelectionSet out.Values[i] = ec._LayerItem_parentId(ctx, field, obj) case "linkedDatasetId": out.Values[i] = ec._LayerItem_linkedDatasetId(ctx, field, obj) + case "tags": + out.Values[i] = ec._LayerItem_tags(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } case "parent": field := field out.Concurrently(i, func() (res graphql.Marshaler) { @@ -36882,12 +37359,39 @@ func (ec *executionContext) _LayerItem(ctx context.Context, sel ast.SelectionSet res = ec._LayerItem_scenePlugin(ctx, field, obj) return res }) - case "tagIds": - out.Values[i] = ec._LayerItem_tagIds(ctx, field, obj) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var layerTagGroupImplementors = []string{"LayerTagGroup", "LayerTag"} + +func (ec *executionContext) _LayerTagGroup(ctx context.Context, sel ast.SelectionSet, obj *gqlmodel.LayerTagGroup) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, layerTagGroupImplementors) + + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("LayerTagGroup") + case "tagId": + out.Values[i] = ec._LayerTagGroup_tagId(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&invalids, 1) } - case "tags": + case "children": + out.Values[i] = ec._LayerTagGroup_children(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "tag": field := field out.Concurrently(i, func() (res graphql.Marshaler) { defer func() { @@ -36895,10 +37399,45 @@ func (ec *executionContext) _LayerItem(ctx context.Context, sel ast.SelectionSet ec.Error(ctx, ec.Recover(ctx, r)) } }() - res = ec._LayerItem_tags(ctx, field, obj) - if res == graphql.Null { - atomic.AddUint32(&invalids, 1) - } + res = ec._LayerTagGroup_tag(ctx, field, obj) + return res + }) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var layerTagItemImplementors = []string{"LayerTagItem", "LayerTag"} + +func (ec *executionContext) _LayerTagItem(ctx context.Context, sel ast.SelectionSet, obj *gqlmodel.LayerTagItem) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, layerTagItemImplementors) + + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("LayerTagItem") + case "tagId": + out.Values[i] = ec._LayerTagItem_tagId(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "tag": + field := field + out.Concurrently(i, func() (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._LayerTagItem_tag(ctx, field, obj) return res }) default: @@ -39523,6 +40062,11 @@ func (ec *executionContext) _RemoveTagPayload(ctx context.Context, sel ast.Selec if out.Values[i] == graphql.Null { invalids++ } + case "updatedLayers": + out.Values[i] = ec._RemoveTagPayload_updatedLayers(ctx, field, obj) + if out.Values[i] == graphql.Null { + invalids++ + } default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -39983,7 +40527,7 @@ func (ec *executionContext) _SyncDatasetPayload(ctx context.Context, sel ast.Sel return out } -var tagGroupImplementors = []string{"TagGroup", "Tag", "Tags"} +var tagGroupImplementors = []string{"TagGroup", "Tag"} func (ec *executionContext) _TagGroup(ctx context.Context, sel ast.SelectionSet, obj *gqlmodel.TagGroup) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, tagGroupImplementors) @@ -39997,20 +40541,59 @@ func (ec *executionContext) _TagGroup(ctx context.Context, sel ast.SelectionSet, case "id": out.Values[i] = ec._TagGroup_id(ctx, field, obj) if out.Values[i] == graphql.Null { - invalids++ + atomic.AddUint32(&invalids, 1) } case "sceneId": out.Values[i] = ec._TagGroup_sceneId(ctx, field, obj) if out.Values[i] == graphql.Null { - invalids++ + atomic.AddUint32(&invalids, 1) } case "label": out.Values[i] = ec._TagGroup_label(ctx, field, obj) if out.Values[i] == graphql.Null { - invalids++ + atomic.AddUint32(&invalids, 1) } + case "tagIds": + out.Values[i] = ec._TagGroup_tagIds(ctx, field, obj) case "tags": - out.Values[i] = ec._TagGroup_tags(ctx, field, obj) + field := field + out.Concurrently(i, func() (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._TagGroup_tags(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + }) + case "scene": + field := field + out.Concurrently(i, func() (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._TagGroup_scene(ctx, field, obj) + return res + }) + case "layers": + field := field + out.Concurrently(i, func() (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._TagGroup_layers(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + }) default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -40022,7 +40605,7 @@ func (ec *executionContext) _TagGroup(ctx context.Context, sel ast.SelectionSet, return out } -var tagItemImplementors = []string{"TagItem", "Tag", "Tags"} +var tagItemImplementors = []string{"TagItem", "Tag"} func (ec *executionContext) _TagItem(ctx context.Context, sel ast.SelectionSet, obj *gqlmodel.TagItem) graphql.Marshaler { fields := graphql.CollectFields(ec.OperationContext, sel, tagItemImplementors) @@ -40048,6 +40631,8 @@ func (ec *executionContext) _TagItem(ctx context.Context, sel ast.SelectionSet, if out.Values[i] == graphql.Null { atomic.AddUint32(&invalids, 1) } + case "parentId": + out.Values[i] = ec._TagItem_parentId(ctx, field, obj) case "linkedDatasetID": out.Values[i] = ec._TagItem_linkedDatasetID(ctx, field, obj) case "linkedDatasetSchemaID": @@ -40087,6 +40672,31 @@ func (ec *executionContext) _TagItem(ctx context.Context, sel ast.SelectionSet, res = ec._TagItem_linkedDatasetField(ctx, field, obj) return res }) + case "parent": + field := field + out.Concurrently(i, func() (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._TagItem_parent(ctx, field, obj) + return res + }) + case "layers": + field := field + out.Concurrently(i, func() (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._TagItem_layers(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + }) default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -42262,6 +42872,114 @@ func (ec *executionContext) marshalNLayerItem2ᚖgithubᚗcomᚋreearthᚋreeart return ec._LayerItem(ctx, sel, v) } +func (ec *executionContext) marshalNLayerTag2githubᚗcomᚋreearthᚋreearthᚑbackendᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐLayerTag(ctx context.Context, sel ast.SelectionSet, v gqlmodel.LayerTag) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + return ec._LayerTag(ctx, sel, v) +} + +func (ec *executionContext) marshalNLayerTag2ᚕgithubᚗcomᚋreearthᚋreearthᚑbackendᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐLayerTagᚄ(ctx context.Context, sel ast.SelectionSet, v []gqlmodel.LayerTag) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNLayerTag2githubᚗcomᚋreearthᚋreearthᚑbackendᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐLayerTag(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalNLayerTagItem2ᚕᚖgithubᚗcomᚋreearthᚋreearthᚑbackendᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐLayerTagItemᚄ(ctx context.Context, sel ast.SelectionSet, v []*gqlmodel.LayerTagItem) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNLayerTagItem2ᚖgithubᚗcomᚋreearthᚋreearthᚑbackendᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐLayerTagItem(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalNLayerTagItem2ᚖgithubᚗcomᚋreearthᚋreearthᚑbackendᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐLayerTagItem(ctx context.Context, sel ast.SelectionSet, v *gqlmodel.LayerTagItem) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + return ec._LayerTagItem(ctx, sel, v) +} + func (ec *executionContext) unmarshalNLinkDatasetToPropertyValueInput2githubᚗcomᚋreearthᚋreearthᚑbackendᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐLinkDatasetToPropertyValueInput(ctx context.Context, v interface{}) (gqlmodel.LinkDatasetToPropertyValueInput, error) { res, err := ec.unmarshalInputLinkDatasetToPropertyValueInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) @@ -43705,6 +44423,50 @@ func (ec *executionContext) marshalNTagGroup2ᚖgithubᚗcomᚋreearthᚋreearth return ec._TagGroup(ctx, sel, v) } +func (ec *executionContext) marshalNTagItem2ᚕᚖgithubᚗcomᚋreearthᚋreearthᚑbackendᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐTagItemᚄ(ctx context.Context, sel ast.SelectionSet, v []*gqlmodel.TagItem) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNTagItem2ᚖgithubᚗcomᚋreearthᚋreearthᚑbackendᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐTagItem(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + func (ec *executionContext) marshalNTagItem2ᚖgithubᚗcomᚋreearthᚋreearthᚑbackendᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐTagItem(ctx context.Context, sel ast.SelectionSet, v *gqlmodel.TagItem) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { @@ -45248,6 +46010,20 @@ func (ec *executionContext) marshalOSyncDatasetPayload2ᚖgithubᚗcomᚋreearth return ec._SyncDatasetPayload(ctx, sel, v) } +func (ec *executionContext) marshalOTag2githubᚗcomᚋreearthᚋreearthᚑbackendᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐTag(ctx context.Context, sel ast.SelectionSet, v gqlmodel.Tag) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._Tag(ctx, sel, v) +} + +func (ec *executionContext) marshalOTagGroup2ᚖgithubᚗcomᚋreearthᚋreearthᚑbackendᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐTagGroup(ctx context.Context, sel ast.SelectionSet, v *gqlmodel.TagGroup) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._TagGroup(ctx, sel, v) +} + func (ec *executionContext) marshalOTeam2ᚖgithubᚗcomᚋreearthᚋreearthᚑbackendᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐTeam(ctx context.Context, sel ast.SelectionSet, v *gqlmodel.Team) graphql.Marshaler { if v == nil { return graphql.Null diff --git a/internal/adapter/gql/gqlmodel/convert_layer.go b/internal/adapter/gql/gqlmodel/convert_layer.go index 9bc9be1a..8863d2bd 100644 --- a/internal/adapter/gql/gqlmodel/convert_layer.go +++ b/internal/adapter/gql/gqlmodel/convert_layer.go @@ -11,12 +11,6 @@ func ToLayerItem(l *layer.Item, parent *id.LayerID) *LayerItem { return nil } - tags := l.Tags().Tags() - tagIDs := make([]*id.ID, 0, len(tags)) - for _, tid := range tags { - tagIDs = append(tagIDs, tid.IDRef()) - } - return &LayerItem{ ID: l.ID().ID(), SceneID: l.Scene().ID(), @@ -28,7 +22,7 @@ func ToLayerItem(l *layer.Item, parent *id.LayerID) *LayerItem { Infobox: ToInfobox(l.Infobox(), l.ID(), l.Scene(), l.LinkedDataset()), LinkedDatasetID: l.LinkedDataset().IDRef(), ParentID: parent.IDRef(), - TagIds: tagIDs, + Tags: ToLayerTagList(l.Tags(), l.Scene()), } } @@ -43,12 +37,6 @@ func ToLayerGroup(l *layer.Group, parent *id.LayerID) *LayerGroup { layers = append(layers, lay.IDRef()) } - tags := l.Tags().Tags() - tagIDs := make([]*id.ID, 0, len(tags)) - for _, tid := range tags { - tagIDs = append(tagIDs, tid.IDRef()) - } - return &LayerGroup{ ID: l.ID().ID(), SceneID: l.Scene().ID(), @@ -62,7 +50,7 @@ func ToLayerGroup(l *layer.Group, parent *id.LayerID) *LayerGroup { LayerIds: layers, Root: l.IsRoot(), ParentID: parent.IDRef(), - TagIds: tagIDs, + Tags: ToLayerTagList(l.Tags(), l.Scene()), } } @@ -188,3 +176,56 @@ func FromLayerEncodingFormat(v LayerEncodingFormat) decoding.LayerEncodingFormat return decoding.LayerEncodingFormat("") } + +func ToLayerTagList(t *layer.TagList, sid id.SceneID) []LayerTag { + if t.IsEmpty() { + return nil + } + tags := t.Tags() + gtags := make([]LayerTag, 0, len(tags)) + for _, t := range tags { + if gt := ToLayerTag(t); gt != nil { + gtags = append(gtags, gt) + } + } + return gtags +} + +func ToLayerTag(l layer.Tag) LayerTag { + if l == nil { + return nil + } + if tg := layer.TagGroupFrom(l); tg != nil { + return ToLayerTagGroup(tg) + } + if ti := layer.TagItemFrom(l); ti != nil { + return ToLayerTagItem(ti) + } + return nil +} + +func ToLayerTagItem(t *layer.TagItem) *LayerTagItem { + if t == nil { + return nil + } + return &LayerTagItem{ + TagID: t.ID().ID(), + } +} + +func ToLayerTagGroup(t *layer.TagGroup) *LayerTagGroup { + if t == nil { + return nil + } + children := t.Children() + tags := make([]*LayerTagItem, 0, len(children)) + for _, c := range children { + if t := ToLayerTagItem(c); t != nil { + tags = append(tags, t) + } + } + return &LayerTagGroup{ + TagID: t.ID().ID(), + Children: tags, + } +} diff --git a/internal/adapter/gql/gqlmodel/convert_tag.go b/internal/adapter/gql/gqlmodel/convert_tag.go index 77ea5103..34de71a7 100644 --- a/internal/adapter/gql/gqlmodel/convert_tag.go +++ b/internal/adapter/gql/gqlmodel/convert_tag.go @@ -13,6 +13,7 @@ func ToTagItem(ti *tag.Item) *TagItem { ID: ti.ID().ID(), SceneID: ti.Scene().ID(), Label: ti.Label(), + ParentID: ti.Parent().IDRef(), LinkedDatasetID: ti.LinkedDatasetID().IDRef(), LinkedDatasetSchemaID: ti.LinkedDatasetSchemaID().IDRef(), LinkedDatasetFieldID: ti.LinkedDatasetFieldID().IDRef(), @@ -34,7 +35,7 @@ func ToTagGroup(tg *tag.Group) *TagGroup { ID: tg.ID().ID(), SceneID: tg.Scene().ID(), Label: tg.Label(), - Tags: ids, + TagIds: ids, } } diff --git a/internal/adapter/gql/gqlmodel/models_gen.go b/internal/adapter/gql/gqlmodel/models_gen.go index 3ddeb118..47e64697 100644 --- a/internal/adapter/gql/gqlmodel/models_gen.go +++ b/internal/adapter/gql/gqlmodel/models_gen.go @@ -19,8 +19,8 @@ type Layer interface { IsLayer() } -type Layers interface { - IsLayers() +type LayerTag interface { + IsLayerTag() } type Node interface { @@ -35,10 +35,6 @@ type Tag interface { IsTag() } -type Tags interface { - IsTags() -} - type AddClusterInput struct { SceneID id.ID `json:"sceneId"` Name string `json:"name"` @@ -262,13 +258,15 @@ type CreateTagGroupPayload struct { type CreateTagItemInput struct { SceneID id.ID `json:"sceneId"` Label string `json:"label"` + Parent *id.ID `json:"parent"` LinkedDatasetSchemaID *id.ID `json:"linkedDatasetSchemaID"` LinkedDatasetID *id.ID `json:"linkedDatasetID"` LinkedDatasetField *id.ID `json:"linkedDatasetField"` } type CreateTagItemPayload struct { - Tag *TagItem `json:"tag"` + Tag *TagItem `json:"tag"` + Parent *TagGroup `json:"parent"` } type CreateTeamInput struct { @@ -490,6 +488,7 @@ type LayerGroup struct { LinkedDatasetSchemaID *id.ID `json:"linkedDatasetSchemaId"` Root bool `json:"root"` LayerIds []*id.ID `json:"layerIds"` + Tags []LayerTag `json:"tags"` Parent *LayerGroup `json:"parent"` Property *Property `json:"property"` Plugin *Plugin `json:"plugin"` @@ -498,12 +497,9 @@ type LayerGroup struct { Layers []Layer `json:"layers"` Scene *Scene `json:"scene"` ScenePlugin *ScenePlugin `json:"scenePlugin"` - TagIds []*id.ID `json:"tagIds"` - Tags []Tag `json:"tags"` } -func (LayerGroup) IsLayers() {} -func (LayerGroup) IsLayer() {} +func (LayerGroup) IsLayer() {} type LayerItem struct { ID id.ID `json:"id"` @@ -516,6 +512,7 @@ type LayerItem struct { Infobox *Infobox `json:"infobox"` ParentID *id.ID `json:"parentId"` LinkedDatasetID *id.ID `json:"linkedDatasetId"` + Tags []LayerTag `json:"tags"` Parent *LayerGroup `json:"parent"` Property *Property `json:"property"` Plugin *Plugin `json:"plugin"` @@ -524,12 +521,24 @@ type LayerItem struct { Merged *MergedLayer `json:"merged"` Scene *Scene `json:"scene"` ScenePlugin *ScenePlugin `json:"scenePlugin"` - TagIds []*id.ID `json:"tagIds"` - Tags []Tag `json:"tags"` } -func (LayerItem) IsLayers() {} -func (LayerItem) IsLayer() {} +func (LayerItem) IsLayer() {} + +type LayerTagGroup struct { + TagID id.ID `json:"tagId"` + Children []*LayerTagItem `json:"children"` + Tag Tag `json:"tag"` +} + +func (LayerTagGroup) IsLayerTag() {} + +type LayerTagItem struct { + TagID id.ID `json:"tagId"` + Tag Tag `json:"tag"` +} + +func (LayerTagItem) IsLayerTag() {} type LinkDatasetToPropertyValueInput struct { PropertyID id.ID `json:"propertyId"` @@ -973,7 +982,8 @@ type RemoveTagInput struct { } type RemoveTagPayload struct { - TagID id.ID `json:"tagId"` + TagID id.ID `json:"tagId"` + UpdatedLayers []Layer `json:"updatedLayers"` } type RemoveWidgetInput struct { @@ -1062,29 +1072,33 @@ type SyncDatasetPayload struct { } type TagGroup struct { - ID id.ID `json:"id"` - SceneID id.ID `json:"sceneId"` - Label string `json:"label"` - Tags []*id.ID `json:"tags"` + ID id.ID `json:"id"` + SceneID id.ID `json:"sceneId"` + Label string `json:"label"` + TagIds []*id.ID `json:"tagIds"` + Tags []*TagItem `json:"tags"` + Scene *Scene `json:"scene"` + Layers []Layer `json:"layers"` } -func (TagGroup) IsTag() {} -func (TagGroup) IsTags() {} +func (TagGroup) IsTag() {} type TagItem struct { ID id.ID `json:"id"` SceneID id.ID `json:"sceneId"` Label string `json:"label"` + ParentID *id.ID `json:"parentId"` LinkedDatasetID *id.ID `json:"linkedDatasetID"` LinkedDatasetSchemaID *id.ID `json:"linkedDatasetSchemaID"` LinkedDatasetFieldID *id.ID `json:"linkedDatasetFieldID"` LinkedDatasetSchema *DatasetSchema `json:"linkedDatasetSchema"` LinkedDataset *Dataset `json:"linkedDataset"` LinkedDatasetField *DatasetField `json:"linkedDatasetField"` + Parent *TagGroup `json:"parent"` + Layers []Layer `json:"layers"` } -func (TagItem) IsTag() {} -func (TagItem) IsTags() {} +func (TagItem) IsTag() {} type Team struct { ID id.ID `json:"id"` diff --git a/internal/adapter/gql/loader_layer.go b/internal/adapter/gql/loader_layer.go index 1beec499..ea982202 100644 --- a/internal/adapter/gql/loader_layer.go +++ b/internal/adapter/gql/loader_layer.go @@ -100,6 +100,24 @@ func (c *LayerLoader) FetchParentAndMerged(ctx context.Context, org id.LayerID) return gqlmodel.ToMergedLayer(res), nil } +func (c *LayerLoader) FetchByTag(ctx context.Context, tag id.TagID) ([]gqlmodel.Layer, error) { + res, err2 := c.usecase.FetchByTag(ctx, tag, getOperator(ctx)) + if err2 != nil { + return nil, err2 + } + + layers := make([]gqlmodel.Layer, 0, len(res)) + for _, l := range res { + if l == nil { + layers = append(layers, nil) + } else { + layers = append(layers, gqlmodel.ToLayer(*l, nil)) + } + } + + return layers, nil +} + // data loader type LayerDataLoader interface { diff --git a/internal/adapter/gql/loader_tag.go b/internal/adapter/gql/loader_tag.go index ab00b7ec..fcfd823e 100644 --- a/internal/adapter/gql/loader_tag.go +++ b/internal/adapter/gql/loader_tag.go @@ -68,73 +68,6 @@ func (c *TagLoader) FetchItem(ctx context.Context, ids []id.TagID) ([]*gqlmodel. return tagItems, nil } -func (c *TagLoader) FetchGroupByLayer(ctx context.Context, lid id.LayerID) ([]*gqlmodel.TagGroup, error) { - res, err := c.usecase.FetchGroupsByLayer(ctx, lid, getOperator(ctx)) - if err != nil { - return nil, err - } - tagGroups := make([]*gqlmodel.TagGroup, 0, len(res)) - for _, t := range res { - tg := gqlmodel.ToTagGroup(t) - if tg != nil { - tagGroups = append(tagGroups, tg) - } - } - - return tagGroups, nil -} - -func (c *TagLoader) FetchItemByLayer(ctx context.Context, lid id.LayerID) ([]*gqlmodel.TagItem, error) { - res, err := c.usecase.FetchItemsByLayer(ctx, lid, getOperator(ctx)) - if err != nil { - return nil, err - } - - tagItems := make([]*gqlmodel.TagItem, 0, len(res)) - for _, t := range res { - ti := gqlmodel.ToTagItem(t) - if ti != nil { - tagItems = append(tagItems, ti) - } - } - - return tagItems, nil -} - -func (c *TagLoader) FetchGroupByScene(ctx context.Context, sid id.SceneID) ([]*gqlmodel.TagGroup, error) { - res, err := c.usecase.FetchGroupsByScene(ctx, sid, getOperator(ctx)) - if err != nil { - return nil, err - } - - tagGroups := make([]*gqlmodel.TagGroup, 0, len(res)) - for _, t := range res { - tg := gqlmodel.ToTagGroup(t) - if tg != nil { - tagGroups = append(tagGroups, tg) - } - } - - return tagGroups, nil -} - -func (c *TagLoader) FetchItemByScene(ctx context.Context, sid id.SceneID) ([]*gqlmodel.TagItem, error) { - res, err := c.usecase.FetchItemsByScene(ctx, sid, getOperator(ctx)) - if err != nil { - return nil, err - } - - tagItems := make([]*gqlmodel.TagItem, 0, len(res)) - for _, t := range res { - ti := gqlmodel.ToTagItem(t) - if ti != nil { - tagItems = append(tagItems, ti) - } - } - - return tagItems, nil -} - // data loaders type TagDataLoader interface { diff --git a/internal/adapter/gql/resolver_layer.go b/internal/adapter/gql/resolver_layer.go index 6c76eda6..1e6ca028 100644 --- a/internal/adapter/gql/resolver_layer.go +++ b/internal/adapter/gql/resolver_layer.go @@ -35,6 +35,14 @@ func (r *Resolver) MergedInfoboxField() MergedInfoboxFieldResolver { return &mergedInfoboxFieldResolver{r} } +func (r *Resolver) LayerTagItem() LayerTagItemResolver { + return &layerTagItemResolver{r} +} + +func (r *Resolver) LayerTagGroup() LayerTagGroupResolver { + return &layerTagGroupResolver{r} +} + type infoboxResolver struct{ *Resolver } func (r *infoboxResolver) Property(ctx context.Context, obj *gqlmodel.Infobox) (*gqlmodel.Property, error) { @@ -202,35 +210,6 @@ func (r *infoboxFieldResolver) ScenePlugin(ctx context.Context, obj *gqlmodel.In type layerGroupResolver struct{ *Resolver } -func (r *layerGroupResolver) Tags(ctx context.Context, obj *gqlmodel.LayerGroup) ([]gqlmodel.Tag, error) { - exit := trace(ctx) - defer exit() - - ids := make([]id.TagID, 0, len(obj.TagIds)) - for _, tid := range obj.TagIds { - if tid != nil { - ids = append(ids, id.TagID(*tid)) - } - } - - tags, err := DataLoadersFromContext(ctx).Tag.LoadAll(ids) - if len(err) > 0 { - for _, err1 := range err { - if err1 != nil { - return nil, err1 - } - } - } - - res := make([]gqlmodel.Tag, 0, len(tags)) - for _, t := range tags { - if t != nil { - res = append(res, *t) - } - } - return res, nil -} - func (r *layerGroupResolver) Parent(ctx context.Context, obj *gqlmodel.LayerGroup) (*gqlmodel.LayerGroup, error) { exit := trace(ctx) defer exit() @@ -411,35 +390,6 @@ func (r *layerItemResolver) ScenePlugin(ctx context.Context, obj *gqlmodel.Layer return s.Plugin(*obj.PluginID), nil } -func (r *layerItemResolver) Tags(ctx context.Context, obj *gqlmodel.LayerItem) ([]gqlmodel.Tag, error) { - exit := trace(ctx) - defer exit() - - ids := make([]id.TagID, 0, len(obj.TagIds)) - for _, tid := range obj.TagIds { - if tid != nil { - ids = append(ids, id.TagID(*tid)) - } - } - - tags, err := DataLoadersFromContext(ctx).Tag.LoadAll(ids) - if len(err) > 0 { - for _, err1 := range err { - if err1 != nil { - return nil, err1 - } - } - } - - res := make([]gqlmodel.Tag, 0, len(tags)) - for _, t := range tags { - if t != nil { - res = append(res, *t) - } - } - return res, nil -} - type mergedLayerResolver struct{ *Resolver } func (r *mergedLayerResolver) Original(ctx context.Context, obj *gqlmodel.MergedLayer) (*gqlmodel.LayerItem, error) { @@ -516,28 +466,28 @@ func (r *mergedInfoboxFieldResolver) ScenePlugin(ctx context.Context, obj *gqlmo return s.Plugin(obj.PluginID), nil } -func (r *mutationResolver) AttachTagToLayer(ctx context.Context, input gqlmodel.AttachTagToLayerInput) (*gqlmodel.AttachTagToLayerPayload, error) { +type layerTagItemResolver struct{ *Resolver } + +func (r *layerTagItemResolver) Tag(ctx context.Context, obj *gqlmodel.LayerTagItem) (gqlmodel.Tag, error) { exit := trace(ctx) defer exit() - layer, err := r.usecases.Layer.AttachTag(ctx, id.LayerID(input.LayerID), id.TagID(input.TagID), getOperator(ctx)) + t, err := DataLoadersFromContext(ctx).Tag.Load(id.TagID(obj.TagID)) if err != nil { return nil, err } - return &gqlmodel.AttachTagToLayerPayload{ - Layer: gqlmodel.ToLayer(layer, nil), - }, nil + return *t, nil } -func (r *mutationResolver) DetachTagFromLayer(ctx context.Context, input gqlmodel.DetachTagFromLayerInput) (*gqlmodel.DetachTagFromLayerPayload, error) { +type layerTagGroupResolver struct{ *Resolver } + +func (r *layerTagGroupResolver) Tag(ctx context.Context, obj *gqlmodel.LayerTagGroup) (gqlmodel.Tag, error) { exit := trace(ctx) defer exit() - layer, err := r.usecases.Layer.DetachTag(ctx, id.LayerID(input.LayerID), id.TagID(input.TagID), getOperator(ctx)) + t, err := DataLoadersFromContext(ctx).Tag.Load(id.TagID(obj.TagID)) if err != nil { return nil, err } - return &gqlmodel.DetachTagFromLayerPayload{ - Layer: gqlmodel.ToLayer(layer, nil), - }, nil + return *t, nil } diff --git a/internal/adapter/gql/resolver_mutation_layer.go b/internal/adapter/gql/resolver_mutation_layer.go index 3b112329..e745793b 100644 --- a/internal/adapter/gql/resolver_mutation_layer.go +++ b/internal/adapter/gql/resolver_mutation_layer.go @@ -214,3 +214,29 @@ func (r *mutationResolver) ImportLayer(ctx context.Context, input gqlmodel.Impor ParentLayer: gqlmodel.ToLayerGroup(l2, nil), }, err } + +func (r *mutationResolver) AttachTagToLayer(ctx context.Context, input gqlmodel.AttachTagToLayerInput) (*gqlmodel.AttachTagToLayerPayload, error) { + exit := trace(ctx) + defer exit() + + layer, err := r.usecases.Layer.AttachTag(ctx, id.LayerID(input.LayerID), id.TagID(input.TagID), getOperator(ctx)) + if err != nil { + return nil, err + } + return &gqlmodel.AttachTagToLayerPayload{ + Layer: gqlmodel.ToLayer(layer, nil), + }, nil +} + +func (r *mutationResolver) DetachTagFromLayer(ctx context.Context, input gqlmodel.DetachTagFromLayerInput) (*gqlmodel.DetachTagFromLayerPayload, error) { + exit := trace(ctx) + defer exit() + + layer, err := r.usecases.Layer.DetachTag(ctx, id.LayerID(input.LayerID), id.TagID(input.TagID), getOperator(ctx)) + if err != nil { + return nil, err + } + return &gqlmodel.DetachTagFromLayerPayload{ + Layer: gqlmodel.ToLayer(layer, nil), + }, nil +} diff --git a/internal/adapter/gql/resolver_mutation_tag.go b/internal/adapter/gql/resolver_mutation_tag.go index 95cc8bd5..ceffc845 100644 --- a/internal/adapter/gql/resolver_mutation_tag.go +++ b/internal/adapter/gql/resolver_mutation_tag.go @@ -12,9 +12,10 @@ func (r *mutationResolver) CreateTagItem(ctx context.Context, input gqlmodel.Cre exit := trace(ctx) defer exit() - tag, err := r.usecases.Tag.CreateItem(ctx, interfaces.CreateTagItemParam{ + tag, parent, err := r.usecases.Tag.CreateItem(ctx, interfaces.CreateTagItemParam{ Label: input.Label, SceneID: id.SceneID(input.SceneID), + Parent: id.TagIDFromRefID(input.Parent), LinkedDatasetSchemaID: id.DatasetSchemaIDFromRefID(input.LinkedDatasetSchemaID), LinkedDatasetID: id.DatasetIDFromRefID(input.LinkedDatasetID), LinkedDatasetField: id.DatasetSchemaFieldIDFromRefID(input.LinkedDatasetField), @@ -22,8 +23,10 @@ func (r *mutationResolver) CreateTagItem(ctx context.Context, input gqlmodel.Cre if err != nil { return nil, err } + return &gqlmodel.CreateTagItemPayload{ - Tag: gqlmodel.ToTagItem(tag), + Tag: gqlmodel.ToTagItem(tag), + Parent: gqlmodel.ToTagGroup(parent), }, nil } @@ -97,11 +100,22 @@ func (r *mutationResolver) RemoveTag(ctx context.Context, input gqlmodel.RemoveT exit := trace(ctx) defer exit() - tagID, err := r.usecases.Tag.Remove(ctx, id.TagID(input.TagID), getOperator(ctx)) + tagID, layers, err := r.usecases.Tag.Remove(ctx, id.TagID(input.TagID), getOperator(ctx)) if err != nil { return nil, err } + + updatedLayers := make([]gqlmodel.Layer, 0, len(layers)) + for _, l := range layers { + if l == nil { + updatedLayers = append(updatedLayers, nil) + } else { + updatedLayers = append(updatedLayers, gqlmodel.ToLayer(*l, nil)) + } + } + return &gqlmodel.RemoveTagPayload{ - TagID: tagID.ID(), + TagID: tagID.ID(), + UpdatedLayers: updatedLayers, }, nil } diff --git a/internal/adapter/gql/resolver_tag.go b/internal/adapter/gql/resolver_tag.go index b3bd77e4..5a378e54 100644 --- a/internal/adapter/gql/resolver_tag.go +++ b/internal/adapter/gql/resolver_tag.go @@ -43,3 +43,58 @@ func (t tagItemResolver) LinkedDatasetField(ctx context.Context, obj *gqlmodel.T ds, err := DataLoadersFromContext(ctx).Dataset.Load(id.DatasetID(*obj.LinkedDatasetID)) return ds.Field(*obj.LinkedDatasetFieldID), err } + +func (t tagItemResolver) Parent(ctx context.Context, obj *gqlmodel.TagItem) (*gqlmodel.TagGroup, error) { + exit := trace(ctx) + defer exit() + + if obj.ParentID == nil { + return nil, nil + } + return DataLoadersFromContext(ctx).TagGroup.Load(id.TagID(*obj.ParentID)) +} + +func (tg tagItemResolver) Layers(ctx context.Context, obj *gqlmodel.TagItem) ([]gqlmodel.Layer, error) { + exit := trace(ctx) + defer exit() + + return tg.loaders.Layer.FetchByTag(ctx, id.TagID(obj.ID)) +} + +type tagGroupResolver struct{ *Resolver } + +func (r *Resolver) TagGroup() TagGroupResolver { + return &tagGroupResolver{r} +} + +func (tg tagGroupResolver) Tags(ctx context.Context, obj *gqlmodel.TagGroup) ([]*gqlmodel.TagItem, error) { + exit := trace(ctx) + defer exit() + + tagIds := make([]id.TagID, 0, len(obj.TagIds)) + for _, i := range obj.TagIds { + if i == nil { + continue + } + tagIds = append(tagIds, id.TagID(*i)) + } + tagItems, err := DataLoadersFromContext(ctx).TagItem.LoadAll(tagIds) + if len(err) > 0 && err[0] != nil { + return nil, err[0] + } + return tagItems, nil +} + +func (tg tagGroupResolver) Scene(ctx context.Context, obj *gqlmodel.TagGroup) (*gqlmodel.Scene, error) { + exit := trace(ctx) + defer exit() + + return DataLoadersFromContext(ctx).Scene.Load(id.SceneID(obj.SceneID)) +} + +func (tg tagGroupResolver) Layers(ctx context.Context, obj *gqlmodel.TagGroup) ([]gqlmodel.Layer, error) { + exit := trace(ctx) + defer exit() + + return tg.loaders.Layer.FetchByTag(ctx, id.TagID(obj.ID)) +} diff --git a/internal/infrastructure/memory/layer.go b/internal/infrastructure/memory/layer.go index c410e927..d59bc308 100644 --- a/internal/infrastructure/memory/layer.go +++ b/internal/infrastructure/memory/layer.go @@ -261,10 +261,8 @@ func (r *Layer) FindByTag(ctx context.Context, tagID id.TagID, s []id.SceneID) ( defer r.lock.Unlock() var res layer.List for _, layer := range r.data { - for _, tag := range layer.Tags().Tags() { - if tag == tagID { - res = append(res, &layer) - } + if layer.Tags().Has(tagID) { + res = append(res, &layer) } } diff --git a/internal/infrastructure/memory/layer_test.go b/internal/infrastructure/memory/layer_test.go index f1e2936c..1ca83948 100644 --- a/internal/infrastructure/memory/layer_test.go +++ b/internal/infrastructure/memory/layer_test.go @@ -15,15 +15,16 @@ func TestLayer_FindByTag(t *testing.T) { sid := id.NewSceneID() sl := []id.SceneID{sid} t1, _ := tag.NewItem().NewID().Scene(sid).Label("item").Build() - tl := tag.NewListFromTags([]id.TagID{t1.ID()}) + tl := layer.NewTagList([]layer.Tag{layer.NewTagGroup(t1.ID(), nil)}) lg := layer.New().NewID().Tags(tl).Scene(sid).Group().MustBuild() + repo := Layer{ data: map[id.LayerID]layer.Layer{ lg.ID(): lg, }, } + out, err := repo.FindByTag(ctx, t1.ID(), sl) assert.NoError(t, err) - l := layer.Layer(lg) - assert.Equal(t, layer.List{&l}, out) + assert.Equal(t, layer.List{lg.LayerRef()}, out) } diff --git a/internal/infrastructure/memory/tag.go b/internal/infrastructure/memory/tag.go index 3b21b5af..2cbba397 100644 --- a/internal/infrastructure/memory/tag.go +++ b/internal/infrastructure/memory/tag.go @@ -112,7 +112,7 @@ func (t *Tag) FindGroupByIDs(ctx context.Context, tagIDs []id.TagID, ids []id.Sc return res, nil } -func (t *Tag) FindByScene(ctx context.Context, sceneID id.SceneID) ([]*tag.Tag, error) { +func (t *Tag) FindRootsByScene(ctx context.Context, sceneID id.SceneID) ([]*tag.Tag, error) { t.lock.Lock() defer t.lock.Unlock() @@ -192,29 +192,3 @@ func (t *Tag) FindGroupByItem(ctx context.Context, tagID id.TagID, s []id.SceneI return nil, rerror.ErrNotFound } - -func (t *Tag) FindGroupByScene(ctx context.Context, sceneID id.SceneID) ([]*tag.Group, error) { - t.lock.Lock() - defer t.lock.Unlock() - - var res []*tag.Group - for _, tt := range t.data { - if group := tag.ToTagGroup(tt); tt.Scene() == sceneID && group != nil { - res = append(res, group) - } - } - return res, nil -} - -func (t *Tag) FindItemByScene(ctx context.Context, sceneID id.SceneID) ([]*tag.Item, error) { - t.lock.Lock() - defer t.lock.Unlock() - - var res []*tag.Item - for _, tt := range t.data { - if item := tag.ToTagItem(tt); tt.Scene() == sceneID && item != nil { - res = append(res, item) - } - } - return res, nil -} diff --git a/internal/infrastructure/memory/tag_test.go b/internal/infrastructure/memory/tag_test.go index b4bfeac2..c6d220bc 100644 --- a/internal/infrastructure/memory/tag_test.go +++ b/internal/infrastructure/memory/tag_test.go @@ -59,7 +59,7 @@ func TestTag_FindByIDs(t *testing.T) { assert.Equal(t, []*tag.Tag{&tti, &ttg}, out) } -func TestTag_FindByScene(t *testing.T) { +func TestTag_FindRootsByScene(t *testing.T) { ctx := context.Background() sid := id.NewSceneID() sid2 := id.NewSceneID() @@ -77,67 +77,11 @@ func TestTag_FindByScene(t *testing.T) { t3.ID(): tti2, }, } - out, err := repo.FindByScene(ctx, sid2) + out, err := repo.FindRootsByScene(ctx, sid2) assert.NoError(t, err) assert.Equal(t, []*tag.Tag{&tti2}, out) } -func TestTag_FindItemByScene(t *testing.T) { - ctx := context.Background() - sid := id.NewSceneID() - sid2 := id.NewSceneID() - t1, _ := tag.NewItem().NewID().Scene(sid).Label("item").Build() - tl := tag.NewListFromTags([]id.TagID{t1.ID()}) - t2, _ := tag.NewGroup().NewID().Scene(sid2).Label("group").Tags(tl).Build() - t3, _ := tag.NewItem().NewID().Scene(sid2).Label("item2").Build() - tti := tag.Tag(t1) - tti2 := tag.Tag(t3) - ttg := tag.Tag(t2) - repo := Tag{ - data: map[id.TagID]tag.Tag{ - t1.ID(): tti, - t2.ID(): ttg, - t3.ID(): tti2, - }, - } - out, err := repo.FindItemByScene(ctx, sid2) - assert.NoError(t, err) - assert.Equal(t, 1, len(out)) - assert.Same(t, t3, out[0]) - - out, err = repo.FindItemByScene(ctx, id.SceneID{}) - assert.NoError(t, err) - assert.Equal(t, 0, len(out)) -} - -func TestTag_FindGroupByScene(t *testing.T) { - ctx := context.Background() - sid := id.NewSceneID() - sid2 := id.NewSceneID() - t1, _ := tag.NewItem().NewID().Scene(sid).Label("item").Build() - tl := tag.NewListFromTags([]id.TagID{t1.ID()}) - t2, _ := tag.NewGroup().NewID().Scene(sid2).Label("group").Tags(tl).Build() - t3, _ := tag.NewItem().NewID().Scene(sid2).Label("item2").Build() - tti := tag.Tag(t1) - tti2 := tag.Tag(t3) - ttg := tag.Tag(t2) - repo := Tag{ - data: map[id.TagID]tag.Tag{ - t1.ID(): tti, - t2.ID(): ttg, - t3.ID(): tti2, - }, - } - out, err := repo.FindGroupByScene(ctx, sid2) - assert.NoError(t, err) - assert.Equal(t, 1, len(out)) - assert.Same(t, t2, out[0]) - - out, err = repo.FindGroupByScene(ctx, id.SceneID{}) - assert.NoError(t, err) - assert.Equal(t, 0, len(out)) -} - func TestTag_FindGroupByID(t *testing.T) { ctx := context.Background() sid := id.NewSceneID() @@ -276,7 +220,7 @@ func TestTag_Remove(t *testing.T) { } err := repo.Remove(ctx, t1.ID()) assert.NoError(t, err) - out, _ := repo.FindByScene(ctx, sid) + out, _ := repo.FindRootsByScene(ctx, sid) assert.Equal(t, []*tag.Tag{&ttg}, out) } @@ -299,7 +243,7 @@ func TestTag_RemoveAll(t *testing.T) { } err := repo.RemoveAll(ctx, []id.TagID{t1.ID(), t3.ID()}) assert.NoError(t, err) - out, _ := repo.FindByScene(ctx, sid) + out, _ := repo.FindRootsByScene(ctx, sid) assert.Equal(t, []*tag.Tag{&tti2}, out) } @@ -323,7 +267,7 @@ func TestTag_RemoveByScene(t *testing.T) { } err := repo.RemoveByScene(ctx, sid) assert.NoError(t, err) - out, _ := repo.FindByScene(ctx, sid2) + out, _ := repo.FindRootsByScene(ctx, sid2) assert.Equal(t, []*tag.Tag{&tti2}, out) } diff --git a/internal/infrastructure/mongo/layer.go b/internal/infrastructure/mongo/layer.go index 3ef8a8f0..efdf02c9 100644 --- a/internal/infrastructure/mongo/layer.go +++ b/internal/infrastructure/mongo/layer.go @@ -31,14 +31,14 @@ func (r *layerRepo) init() { } func (r *layerRepo) FindByID(ctx context.Context, id id.LayerID, f []id.SceneID) (layer.Layer, error) { - filter := r.sceneFilter(bson.D{ + filter := r.sceneFilterD(bson.D{ {Key: "id", Value: id.String()}, }, f) return r.findOne(ctx, filter) } func (r *layerRepo) FindByIDs(ctx context.Context, ids []id.LayerID, f []id.SceneID) (layer.List, error) { - filter := r.sceneFilter(bson.D{ + filter := r.sceneFilterD(bson.D{ {Key: "id", Value: bson.D{ {Key: "$in", Value: id.LayerIDToKeys(ids)}, }}, @@ -59,14 +59,14 @@ func (r *layerRepo) FindAllByDatasetSchema(ctx context.Context, dsid id.DatasetS } func (r *layerRepo) FindItemByID(ctx context.Context, id id.LayerID, f []id.SceneID) (*layer.Item, error) { - filter := r.sceneFilter(bson.D{ + filter := r.sceneFilterD(bson.D{ {Key: "id", Value: id.String()}, }, f) return r.findItemOne(ctx, filter) } func (r *layerRepo) FindItemByIDs(ctx context.Context, ids []id.LayerID, f []id.SceneID) (layer.ItemList, error) { - filter := r.sceneFilter(bson.D{ + filter := r.sceneFilterD(bson.D{ {Key: "id", Value: bson.D{ {Key: "$in", Value: id.LayerIDToKeys(ids)}, }}, @@ -80,14 +80,14 @@ func (r *layerRepo) FindItemByIDs(ctx context.Context, ids []id.LayerID, f []id. } func (r *layerRepo) FindGroupByID(ctx context.Context, id id.LayerID, f []id.SceneID) (*layer.Group, error) { - filter := r.sceneFilter(bson.D{ + filter := r.sceneFilterD(bson.D{ {Key: "id", Value: id.String()}, }, f) return r.findGroupOne(ctx, filter) } func (r *layerRepo) FindGroupByIDs(ctx context.Context, ids []id.LayerID, f []id.SceneID) (layer.GroupList, error) { - filter := r.sceneFilter(bson.D{ + filter := r.sceneFilterD(bson.D{ {Key: "id", Value: bson.D{ {Key: "$in", Value: id.LayerIDToKeys(ids)}, }}, @@ -109,7 +109,7 @@ func (r *layerRepo) FindGroupBySceneAndLinkedDatasetSchema(ctx context.Context, } func (r *layerRepo) FindByProperty(ctx context.Context, id id.PropertyID, f []id.SceneID) (layer.Layer, error) { - filter := r.sceneFilter(bson.D{ + filter := r.sceneFilterD(bson.D{ {Key: "$or", Value: []bson.D{ {{Key: "property", Value: id.String()}}, {{Key: "infobox.property", Value: id.String()}}, @@ -120,7 +120,7 @@ func (r *layerRepo) FindByProperty(ctx context.Context, id id.PropertyID, f []id } func (r *layerRepo) FindParentByID(ctx context.Context, id id.LayerID, f []id.SceneID) (*layer.Group, error) { - filter := r.sceneFilter(bson.D{ + filter := r.sceneFilterD(bson.D{ {Key: "group.layers", Value: id.String()}, }, f) return r.findGroupOne(ctx, filter) @@ -170,16 +170,18 @@ func (r *layerRepo) RemoveByScene(ctx context.Context, sceneID id.SceneID) error func (r *layerRepo) FindByTag(ctx context.Context, tagID id.TagID, f []id.SceneID) (layer.List, error) { ids := []id.TagID{tagID} - filter := r.sceneFilter(bson.D{ - {Key: "tags", Value: bson.D{ - {Key: "$in", Value: id.TagIDToKeys(ids)}, - }}, + tags := id.TagIDToKeys(ids) + filter := r.sceneFilter(bson.M{ + "$or": []bson.M{ + {"tags.id": bson.M{"$in": tags}}, + {"tags.tags.id": bson.M{"$in": tags}}, + }, }, f) return r.find(ctx, nil, filter) } -func (r *layerRepo) find(ctx context.Context, dst layer.List, filter bson.D) (layer.List, error) { +func (r *layerRepo) find(ctx context.Context, dst layer.List, filter interface{}) (layer.List, error) { c := mongodoc.LayerConsumer{ Rows: dst, } @@ -323,7 +325,7 @@ func filterLayerGroups(ids []id.LayerID, rows []*layer.Group) []*layer.Group { return res } -func (*layerRepo) sceneFilter(filter bson.D, scenes []id.SceneID) bson.D { +func (*layerRepo) sceneFilterD(filter bson.D, scenes []id.SceneID) bson.D { if scenes == nil { return filter } @@ -333,3 +335,11 @@ func (*layerRepo) sceneFilter(filter bson.D, scenes []id.SceneID) bson.D { }) return filter } + +func (*layerRepo) sceneFilter(filter bson.M, scenes []id.SceneID) bson.M { + if scenes == nil { + return filter + } + filter["scene"] = bson.M{"$in": id.SceneIDToKeys(scenes)} + return filter +} diff --git a/internal/infrastructure/mongo/mongodoc/layer.go b/internal/infrastructure/mongo/mongodoc/layer.go index 1c3b0ac8..44b935a9 100644 --- a/internal/infrastructure/mongo/mongodoc/layer.go +++ b/internal/infrastructure/mongo/mongodoc/layer.go @@ -3,12 +3,9 @@ package mongodoc import ( "errors" - "github.com/reearth/reearth-backend/pkg/tag" - - "go.mongodb.org/mongo-driver/bson" - "github.com/reearth/reearth-backend/pkg/id" "github.com/reearth/reearth-backend/pkg/layer" + "go.mongodb.org/mongo-driver/bson" ) type LayerInfoboxFieldDocument struct { @@ -23,6 +20,14 @@ type LayerInfoboxDocument struct { Fields []LayerInfoboxFieldDocument } +type LayerTagDocument struct { + ID string + Group bool + Tags []LayerTagDocument +} + +type LayerTagListDocument []LayerTagDocument + type LayerItemDocument struct { LinkedDataset *string } @@ -44,7 +49,7 @@ type LayerDocument struct { Infobox *LayerInfoboxDocument Item *LayerItemDocument Group *LayerGroupDocument - Tags []string + Tags LayerTagListDocument } type LayerConsumer struct { @@ -114,11 +119,7 @@ func NewLayer(l layer.Layer) (*LayerDocument, string) { Fields: fields, } } - var tagIDs []string - tags := l.Tags() - for _, tid := range tags.Tags() { - tagIDs = append(tagIDs, tid.String()) - } + id := l.ID().String() return &LayerDocument{ ID: id, @@ -131,7 +132,7 @@ func NewLayer(l layer.Layer) (*LayerDocument, string) { Plugin: l.Plugin().StringRef(), Extension: l.Extension().StringRef(), Property: l.Property().StringRef(), - Tags: tagIDs, + Tags: NewLayerTagList(l.Tags()), }, id } @@ -181,12 +182,6 @@ func (d *LayerDocument) ModelItem() (*layer.Item, error) { return nil, err } - tids, err := id.TagIDsFrom(d.Tags) - if err != nil { - return nil, err - } - tagList := tag.NewListFromTags(tids) - return layer.NewItem(). ID(lid). Name(d.Name). @@ -196,7 +191,7 @@ func (d *LayerDocument) ModelItem() (*layer.Item, error) { Property(id.PropertyIDFromRef(d.Property)). Infobox(ib). Scene(sid). - Tags(tagList). + Tags(d.Tags.Model()). // item LinkedDataset(id.DatasetIDFromRef(d.Item.LinkedDataset)). Build() @@ -225,12 +220,6 @@ func (d *LayerDocument) ModelGroup() (*layer.Group, error) { ids = append(ids, lid) } - tids, err := id.TagIDsFrom(d.Tags) - if err != nil { - return nil, err - } - tagList := tag.NewListFromTags(tids) - return layer.NewGroup(). ID(lid). Name(d.Name). @@ -240,7 +229,7 @@ func (d *LayerDocument) ModelGroup() (*layer.Group, error) { Property(id.PropertyIDFromRef(d.Property)). Infobox(ib). Scene(sid). - Tags(tagList). + Tags(d.Tags.Model()). // group Root(d.Group != nil && d.Group.Root). Layers(layer.NewIDList(ids)). @@ -283,3 +272,83 @@ func ToModelInfobox(ib *LayerInfoboxDocument) (*layer.Infobox, error) { } return layer.NewInfobox(fields, pid), nil } + +func NewLayerTagList(list *layer.TagList) LayerTagListDocument { + if list.IsEmpty() { + return nil + } + + tags := list.Tags() + if len(tags) == 0 { + return nil + } + res := make([]LayerTagDocument, 0, len(tags)) + for _, t := range tags { + if t == nil { + return nil + } + if td := NewLayerTag(t); td != nil { + res = append(res, *td) + } + } + return res +} + +func (d *LayerTagListDocument) Model() *layer.TagList { + if d == nil { + return nil + } + + tags := make([]layer.Tag, 0, len(*d)) + for _, t := range *d { + if ti := t.Model(); ti != nil { + tags = append(tags, ti) + } + } + return layer.NewTagList(tags) +} + +func NewLayerTag(t layer.Tag) *LayerTagDocument { + var group bool + var tags []LayerTagDocument + + if tg := layer.TagGroupFrom(t); tg != nil { + group = true + children := tg.Children() + tags = make([]LayerTagDocument, 0, len(children)) + for _, c := range children { + if ct := NewLayerTag(c); ct != nil { + tags = append(tags, *ct) + } + } + } else if ti := layer.TagItemFrom(t); ti == nil { + return nil + } + return &LayerTagDocument{ + ID: t.ID().String(), + Group: group, + Tags: tags, + } +} + +func (d *LayerTagDocument) Model() layer.Tag { + if d == nil { + return nil + } + + tid := id.TagIDFromRef(&d.ID) + if tid == nil { + return nil + } + + if d.Group { + tags := make([]*layer.TagItem, 0, len(d.Tags)) + for _, t := range d.Tags { + if ti := layer.TagItemFrom(t.Model()); ti != nil { + tags = append(tags, ti) + } + } + return layer.NewTagGroup(*tid, tags) + } + return layer.NewTagItem(*tid) +} diff --git a/internal/infrastructure/mongo/mongodoc/tag.go b/internal/infrastructure/mongo/mongodoc/tag.go index 68ff9cfd..d8e936f3 100644 --- a/internal/infrastructure/mongo/mongodoc/tag.go +++ b/internal/infrastructure/mongo/mongodoc/tag.go @@ -10,6 +10,7 @@ import ( ) type TagItemDocument struct { + Parent *string LinkedDatasetFieldID *string LinkedDatasetID *string LinkedDatasetSchemaID *string @@ -73,6 +74,7 @@ func NewTag(t tag.Tag) (*TagDocument, string) { if ti := tag.ItemFrom(t); ti != nil { item = &TagItemDocument{ + Parent: ti.Parent().StringRef(), LinkedDatasetFieldID: ti.LinkedDatasetFieldID().StringRef(), LinkedDatasetID: ti.LinkedDatasetID().StringRef(), LinkedDatasetSchemaID: ti.LinkedDatasetSchemaID().StringRef(), @@ -111,6 +113,7 @@ func (d *TagDocument) Model() (*tag.Item, *tag.Group, error) { } return ti, nil, nil } + if d.Group != nil { tg, err := d.ModelGroup() if err != nil { @@ -118,10 +121,15 @@ func (d *TagDocument) Model() (*tag.Item, *tag.Group, error) { } return nil, tg, nil } + return nil, nil, errors.New("invalid tag") } func (d *TagDocument) ModelItem() (*tag.Item, error) { + if d.Item == nil { + return nil, nil + } + tid, err := id.TagIDFrom(d.ID) if err != nil { return nil, err @@ -135,6 +143,7 @@ func (d *TagDocument) ModelItem() (*tag.Item, error) { ID(tid). Label(d.Label). Scene(sid). + Parent(id.TagIDFromRef(d.Item.Parent)). LinkedDatasetSchemaID(id.DatasetSchemaIDFromRef(d.Item.LinkedDatasetSchemaID)). LinkedDatasetID(id.DatasetIDFromRef(d.Item.LinkedDatasetID)). LinkedDatasetFieldID(id.DatasetSchemaFieldIDFromRef(d.Item.LinkedDatasetFieldID)). @@ -142,6 +151,10 @@ func (d *TagDocument) ModelItem() (*tag.Item, error) { } func (d *TagDocument) ModelGroup() (*tag.Group, error) { + if d.Group == nil { + return nil, nil + } + tid, err := id.TagIDFrom(d.ID) if err != nil { return nil, err diff --git a/internal/infrastructure/mongo/mongodoc/tag_test.go b/internal/infrastructure/mongo/mongodoc/tag_test.go index ed9d3092..b4d1869e 100644 --- a/internal/infrastructure/mongo/mongodoc/tag_test.go +++ b/internal/infrastructure/mongo/mongodoc/tag_test.go @@ -352,7 +352,8 @@ func TestTagDocument_ModelGroup(t *testing.T) { { name: "invalid id", fields: fields{ - ID: "xxx", + ID: "xxx", + Group: &TagGroupDocument{}, }, want: nil, wantErr: true, @@ -362,6 +363,7 @@ func TestTagDocument_ModelGroup(t *testing.T) { fields: fields{ ID: id.NewTagID().String(), Scene: "xxx", + Group: &TagGroupDocument{}, }, want: nil, wantErr: true, @@ -439,7 +441,8 @@ func TestTagDocument_ModelItem(t *testing.T) { { name: "invalid id", fields: fields{ - ID: "xxx", + ID: "xxx", + Item: &TagItemDocument{}, }, want: nil, wantErr: true, @@ -449,6 +452,7 @@ func TestTagDocument_ModelItem(t *testing.T) { fields: fields{ ID: id.NewTagID().String(), Scene: "xxx", + Item: &TagItemDocument{}, }, want: nil, wantErr: true, diff --git a/internal/infrastructure/mongo/tag.go b/internal/infrastructure/mongo/tag.go index 58175649..f07349aa 100644 --- a/internal/infrastructure/mongo/tag.go +++ b/internal/infrastructure/mongo/tag.go @@ -93,27 +93,14 @@ func (r *tagRepo) FindGroupByIDs(ctx context.Context, ids []id.TagID, f []id.Sce return filterTagGroups(ids, res), nil } -func (r *tagRepo) FindByScene(ctx context.Context, id id.SceneID) ([]*tag.Tag, error) { - filter := bson.D{ - {Key: "scene", Value: id.String()}, +func (r *tagRepo) FindRootsByScene(ctx context.Context, id id.SceneID) ([]*tag.Tag, error) { + filter := bson.M{ + "scene": id.String(), + "item.parent": nil, } return r.find(ctx, nil, filter) } -func (r *tagRepo) FindGroupByScene(ctx context.Context, id id.SceneID) ([]*tag.Group, error) { - filter := bson.D{ - {Key: "scene", Value: id.String()}, - } - return r.findGroups(ctx, nil, filter) -} - -func (r *tagRepo) FindItemByScene(ctx context.Context, id id.SceneID) ([]*tag.Item, error) { - filter := bson.D{ - {Key: "scene", Value: id.String()}, - } - return r.findItems(ctx, nil, filter) -} - func (r *tagRepo) FindGroupByItem(ctx context.Context, tagID id.TagID, f []id.SceneID) (*tag.Group, error) { ids := []id.TagID{tagID} filter := r.sceneFilter(bson.D{ @@ -160,7 +147,7 @@ func (r *tagRepo) RemoveByScene(ctx context.Context, sceneID id.SceneID) error { return nil } -func (r *tagRepo) find(ctx context.Context, dst []*tag.Tag, filter bson.D) ([]*tag.Tag, error) { +func (r *tagRepo) find(ctx context.Context, dst []*tag.Tag, filter interface{}) ([]*tag.Tag, error) { c := mongodoc.TagConsumer{ Rows: dst, } @@ -170,7 +157,7 @@ func (r *tagRepo) find(ctx context.Context, dst []*tag.Tag, filter bson.D) ([]*t return c.Rows, nil } -func (r *tagRepo) findOne(ctx context.Context, filter bson.D) (tag.Tag, error) { +func (r *tagRepo) findOne(ctx context.Context, filter interface{}) (tag.Tag, error) { c := mongodoc.TagConsumer{} if err := r.client.FindOne(ctx, filter, &c); err != nil { return nil, err diff --git a/internal/usecase/interactor/layer.go b/internal/usecase/interactor/layer.go index e6e62187..e7f1b348 100644 --- a/internal/usecase/interactor/layer.go +++ b/internal/usecase/interactor/layer.go @@ -10,6 +10,7 @@ import ( "github.com/reearth/reearth-backend/internal/usecase/interfaces" "github.com/reearth/reearth-backend/pkg/rerror" "github.com/reearth/reearth-backend/pkg/shp" + "github.com/reearth/reearth-backend/pkg/tag" "github.com/reearth/reearth-backend/internal/usecase" "github.com/reearth/reearth-backend/internal/usecase/repo" @@ -29,6 +30,7 @@ type Layer struct { commonScene commonSceneLock layerRepo repo.Layer + tagRepo repo.Tag pluginRepo repo.Plugin propertyRepo repo.Property propertySchemaRepo repo.PropertySchema @@ -44,6 +46,7 @@ func NewLayer(r *repo.Container) interfaces.Layer { commonScene: commonScene{sceneRepo: r.Scene}, commonSceneLock: commonSceneLock{sceneLockRepo: r.SceneLock}, layerRepo: r.Layer, + tagRepo: r.Tag, pluginRepo: r.Plugin, propertyRepo: r.Property, datasetRepo: r.Dataset, @@ -55,7 +58,7 @@ func NewLayer(r *repo.Container) interfaces.Layer { } } -func (i *Layer) Fetch(ctx context.Context, ids []id.LayerID, operator *usecase.Operator) ([]*layer.Layer, error) { +func (i *Layer) Fetch(ctx context.Context, ids []id.LayerID, operator *usecase.Operator) (layer.List, error) { scenes, err := i.OnlyReadableScenes(ctx, operator) if err != nil { return nil, err @@ -151,6 +154,14 @@ func (i *Layer) FetchParentAndMerged(ctx context.Context, org id.LayerID, operat return layer.Merge(orgl, parent), nil } +func (i *Layer) FetchByTag(ctx context.Context, tag id.TagID, operator *usecase.Operator) (layer.List, error) { + scenes, err := i.OnlyReadableScenes(ctx, operator) + if err != nil { + return nil, err + } + return i.layerRepo.FindByTag(ctx, tag, scenes) +} + func (i *Layer) AddItem(ctx context.Context, inp interfaces.AddLayerItemInput, operator *usecase.Operator) (_ *layer.Item, _ *layer.Group, err error) { tx, err := i.transaction.Begin() if err != nil { @@ -1023,21 +1034,36 @@ func (i *Layer) AttachTag(ctx context.Context, layerID id.LayerID, tagID id.TagI return nil, err } - layer, err := i.layerRepo.FindByID(ctx, layerID, scenes) + // ensure the tag exists + t, err := i.tagRepo.FindByID(ctx, tagID, scenes) if err != nil { return nil, err } - if err := layer.AttachTag(tagID); err != nil { - return nil, err - } - err = i.layerRepo.Save(ctx, layer) + l, err := i.layerRepo.FindByID(ctx, layerID, scenes) if err != nil { return nil, err } + updated := false + if tg := tag.ToTagGroup(t); tg != nil { + updated = l.Tags().Add(layer.NewTagGroup(tagID, nil)) + } else if ti := tag.ToTagItem(t); ti != nil { + if p := ti.Parent(); p != nil { + updated = l.Tags().FindGroup(*ti.Parent()).Add(layer.NewTagItem(ti.ID())) + } else { + updated = l.Tags().Add(layer.NewTagItem(ti.ID())) + } + } + + if updated { + if err := i.layerRepo.Save(ctx, l); err != nil { + return nil, err + } + } + tx.Commit() - return layer, nil + return l, nil } func (i *Layer) DetachTag(ctx context.Context, layerID id.LayerID, tagID id.TagID, operator *usecase.Operator) (layer.Layer, error) { @@ -1061,12 +1087,10 @@ func (i *Layer) DetachTag(ctx context.Context, layerID id.LayerID, tagID id.TagI return nil, err } - if err := layer.DetachTag(tagID); err != nil { - return nil, err - } - err = i.layerRepo.Save(ctx, layer) - if err != nil { - return nil, err + if layer.Tags().Delete(tagID) { + if err := i.layerRepo.Save(ctx, layer); err != nil { + return nil, err + } } tx.Commit() diff --git a/internal/usecase/interactor/tag.go b/internal/usecase/interactor/tag.go index 9cb15da5..5beb030b 100644 --- a/internal/usecase/interactor/tag.go +++ b/internal/usecase/interactor/tag.go @@ -8,6 +8,7 @@ import ( "github.com/reearth/reearth-backend/internal/usecase/interfaces" "github.com/reearth/reearth-backend/internal/usecase/repo" "github.com/reearth/reearth-backend/pkg/id" + "github.com/reearth/reearth-backend/pkg/layer" "github.com/reearth/reearth-backend/pkg/rerror" "github.com/reearth/reearth-backend/pkg/tag" ) @@ -30,10 +31,10 @@ func NewTag(r *repo.Container) interfaces.Tag { } } -func (i *Tag) CreateItem(ctx context.Context, inp interfaces.CreateTagItemParam, operator *usecase.Operator) (*tag.Item, error) { +func (i *Tag) CreateItem(ctx context.Context, inp interfaces.CreateTagItemParam, operator *usecase.Operator) (*tag.Item, *tag.Group, error) { tx, err := i.transaction.Begin() if err != nil { - return nil, err + return nil, nil, err } defer func() { if err2 := tx.End(ctx); err == nil && err2 != nil { @@ -42,13 +43,22 @@ func (i *Tag) CreateItem(ctx context.Context, inp interfaces.CreateTagItemParam, }() if err := i.CanWriteScene(ctx, inp.SceneID, operator); err != nil { - return nil, interfaces.ErrOperationDenied + return nil, nil, interfaces.ErrOperationDenied + } + + var parent *tag.Group + if inp.Parent != nil { + parent, err = i.tagRepo.FindGroupByID(ctx, *inp.Parent, []id.SceneID{inp.SceneID}) + if err != nil { + return nil, nil, err + } } builder := tag.NewItem(). NewID(). Label(inp.Label). - Scene(inp.SceneID) + Scene(inp.SceneID). + Parent(inp.Parent) if inp.LinkedDatasetSchemaID != nil && inp.LinkedDatasetID != nil && inp.LinkedDatasetField != nil { builder = builder. LinkedDatasetFieldID(inp.LinkedDatasetField). @@ -57,15 +67,25 @@ func (i *Tag) CreateItem(ctx context.Context, inp interfaces.CreateTagItemParam, } item, err := builder.Build() if err != nil { - return nil, err + return nil, nil, err } - err = i.tagRepo.Save(ctx, item) - if err != nil { - return nil, err + if parent != nil { + parent.Tags().Add(item.ID()) } + + itemt := tag.Tag(item) + tags := []*tag.Tag{&itemt} + if parent != nil { + parentt := tag.Tag(parent) + tags = append(tags, &parentt) + } + if err := i.tagRepo.SaveAll(ctx, tags); err != nil { + return nil, nil, err + } + tx.Commit() - return item, nil + return item, parent, nil } func (i *Tag) CreateGroup(ctx context.Context, inp interfaces.CreateTagGroupParam, operator *usecase.Operator) (*tag.Group, error) { @@ -118,7 +138,7 @@ func (i *Tag) FetchByScene(ctx context.Context, sid id.SceneID, operator *usecas return nil, err } - return i.tagRepo.FindByScene(ctx, sid) + return i.tagRepo.FindRootsByScene(ctx, sid) } func (i *Tag) FetchItem(ctx context.Context, ids []id.TagID, operator *usecase.Operator) ([]*tag.Item, error) { @@ -139,51 +159,6 @@ func (i *Tag) FetchGroup(ctx context.Context, ids []id.TagID, operator *usecase. return i.tagRepo.FindGroupByIDs(ctx, ids, scenes) } -func (i *Tag) FetchGroupsByLayer(ctx context.Context, lid id.LayerID, operator *usecase.Operator) ([]*tag.Group, error) { - scenes, err := i.OnlyReadableScenes(ctx, operator) - if err != nil { - return nil, err - } - - layer, err := i.layerRepo.FindByID(ctx, lid, scenes) - if err != nil { - return nil, err - } - - return i.tagRepo.FindGroupByIDs(ctx, layer.Tags().Tags(), scenes) -} - -func (i *Tag) FetchGroupsByScene(ctx context.Context, sid id.SceneID, operator *usecase.Operator) ([]*tag.Group, error) { - err := i.CanReadScene(ctx, sid, operator) - if err != nil { - return nil, err - } - - return i.tagRepo.FindGroupByScene(ctx, sid) -} - -func (i *Tag) FetchItemsByLayer(ctx context.Context, lid id.LayerID, operator *usecase.Operator) ([]*tag.Item, error) { - scenes, err := i.OnlyReadableScenes(ctx, operator) - if err != nil { - return nil, err - } - - layer, err := i.layerRepo.FindByID(ctx, lid, scenes) - if err != nil { - return nil, err - } - return i.tagRepo.FindItemByIDs(ctx, layer.Tags().Tags(), scenes) -} - -func (i *Tag) FetchItemsByScene(ctx context.Context, sid id.SceneID, operator *usecase.Operator) ([]*tag.Item, error) { - err := i.CanReadScene(ctx, sid, operator) - if err != nil { - return nil, err - } - - return i.tagRepo.FindItemByScene(ctx, sid) -} - func (i *Tag) AttachItemToGroup(ctx context.Context, inp interfaces.AttachItemToGroupParam, operator *usecase.Operator) (*tag.Group, error) { tx, err := i.transaction.Begin() if err != nil { @@ -199,25 +174,34 @@ func (i *Tag) AttachItemToGroup(ctx context.Context, inp interfaces.AttachItemTo if err != nil { return nil, err } + // make sure item exist - _, err = i.tagRepo.FindItemByID(ctx, inp.ItemID, scenes) + ti, err := i.tagRepo.FindItemByID(ctx, inp.ItemID, scenes) if err != nil { return nil, err } + if ti.Parent() != nil { + return nil, errors.New("tag is already added to the group") + } tg, err := i.tagRepo.FindGroupByID(ctx, inp.GroupID, scenes) if err != nil { return nil, err } - if !tg.Tags().Has(inp.ItemID) { - tg.Tags().Add(inp.ItemID) - } else { + + if tg.Tags().Has(inp.ItemID) { return nil, errors.New("tag item is already attached to the group") } - err = i.tagRepo.Save(ctx, tg) - if err != nil { + + tg.Tags().Add(inp.ItemID) + ti.SetParent(tg.ID().Ref()) + + tgt := tag.Tag(tg) + tit := tag.Tag(ti) + if err := i.tagRepo.SaveAll(ctx, []*tag.Tag{&tgt, &tit}); err != nil { return nil, err } + tx.Commit() return tg, nil } @@ -237,8 +221,9 @@ func (i *Tag) DetachItemFromGroup(ctx context.Context, inp interfaces.DetachItem if err != nil { return nil, err } + // make sure item exist - _, err = i.tagRepo.FindItemByID(ctx, inp.ItemID, scenes) + ti, err := i.tagRepo.FindItemByID(ctx, inp.ItemID, scenes) if err != nil { return nil, err } @@ -247,14 +232,17 @@ func (i *Tag) DetachItemFromGroup(ctx context.Context, inp interfaces.DetachItem if err != nil { return nil, err } - if tg.Tags().Has(inp.ItemID) { - tg.Tags().Remove(inp.ItemID) - } else { + + if !tg.Tags().Has(inp.ItemID) { return nil, errors.New("tag item is not attached to the group") } - err = i.tagRepo.Save(ctx, tg) - if err != nil { + tg.Tags().Remove(inp.ItemID) + ti.SetParent(nil) + + tgt := tag.Tag(tg) + tit := tag.Tag(ti) + if err := i.tagRepo.SaveAll(ctx, []*tag.Tag{&tgt, &tit}); err != nil { return nil, err } @@ -294,11 +282,10 @@ func (i *Tag) UpdateTag(ctx context.Context, inp interfaces.UpdateTagParam, oper return &tg, nil } -func (i *Tag) Remove(ctx context.Context, tagID id.TagID, operator *usecase.Operator) (*id.TagID, error) { +func (i *Tag) Remove(ctx context.Context, tagID id.TagID, operator *usecase.Operator) (*id.TagID, layer.List, error) { tx, err := i.transaction.Begin() - if err != nil { - return nil, err + return nil, nil, err } defer func() { if err2 := tx.End(ctx); err == nil && err2 != nil { @@ -308,55 +295,50 @@ func (i *Tag) Remove(ctx context.Context, tagID id.TagID, operator *usecase.Oper scenes, err := i.OnlyWritableScenes(ctx, operator) if err != nil { - return nil, err + return nil, nil, err } t, err := i.tagRepo.FindByID(ctx, tagID, scenes) if err != nil { - return nil, err + return nil, nil, err } if group := tag.ToTagGroup(t); group != nil { - tags := group.Tags() - if len(tags.Tags()) != 0 { - return nil, interfaces.ErrNonemptyTagGroupCannotDelete + if len(group.Tags().Tags()) != 0 { + return nil, nil, interfaces.ErrNonemptyTagGroupCannotDelete } } if item := tag.ToTagItem(t); item != nil { g, err := i.tagRepo.FindGroupByItem(ctx, item.ID(), scenes) if err != nil && !errors.Is(rerror.ErrNotFound, err) { - return nil, err + return nil, nil, err } if g != nil { g.Tags().Remove(item.ID()) - - err = i.tagRepo.Save(ctx, g) - if err != nil { - return nil, err + if err := i.tagRepo.Save(ctx, g); err != nil { + return nil, nil, err } } } ls, err := i.layerRepo.FindByTag(ctx, tagID, scenes) if err != nil && !errors.Is(rerror.ErrNotFound, err) { - return nil, err + return nil, nil, err } - if ls != nil && len(ls) > 0 { + if len(ls) != 0 { for _, l := range ls.Deref() { - err = l.DetachTag(tagID) - if err != nil { - return nil, err - } + _ = l.Tags().Delete(tagID) } if err := i.layerRepo.SaveAll(ctx, ls); err != nil { - return nil, err + return nil, nil, err } } if err := i.tagRepo.Remove(ctx, tagID); err != nil { - return nil, err + return nil, nil, err } - return &tagID, nil + + return &tagID, ls, nil } diff --git a/internal/usecase/interfaces/layer.go b/internal/usecase/interfaces/layer.go index 887f4563..c4c9f290 100644 --- a/internal/usecase/interfaces/layer.go +++ b/internal/usecase/interfaces/layer.go @@ -84,13 +84,14 @@ var ( ) type Layer interface { - Fetch(context.Context, []id.LayerID, *usecase.Operator) ([]*layer.Layer, error) + Fetch(context.Context, []id.LayerID, *usecase.Operator) (layer.List, error) FetchGroup(context.Context, []id.LayerID, *usecase.Operator) ([]*layer.Group, error) FetchItem(context.Context, []id.LayerID, *usecase.Operator) ([]*layer.Item, error) FetchParent(context.Context, id.LayerID, *usecase.Operator) (*layer.Group, error) FetchByProperty(context.Context, id.PropertyID, *usecase.Operator) (layer.Layer, error) FetchMerged(context.Context, id.LayerID, *id.LayerID, *usecase.Operator) (*layer.Merged, error) FetchParentAndMerged(context.Context, id.LayerID, *usecase.Operator) (*layer.Merged, error) + FetchByTag(context.Context, id.TagID, *usecase.Operator) (layer.List, error) AddItem(context.Context, AddLayerItemInput, *usecase.Operator) (*layer.Item, *layer.Group, error) AddGroup(context.Context, AddLayerGroupInput, *usecase.Operator) (*layer.Group, *layer.Group, error) Remove(context.Context, id.LayerID, *usecase.Operator) (id.LayerID, *layer.Group, error) diff --git a/internal/usecase/interfaces/tag.go b/internal/usecase/interfaces/tag.go index af703d93..0aec3dbb 100644 --- a/internal/usecase/interfaces/tag.go +++ b/internal/usecase/interfaces/tag.go @@ -6,6 +6,7 @@ import ( "github.com/reearth/reearth-backend/internal/usecase" "github.com/reearth/reearth-backend/pkg/id" + "github.com/reearth/reearth-backend/pkg/layer" "github.com/reearth/reearth-backend/pkg/tag" ) @@ -16,6 +17,7 @@ var ( type CreateTagItemParam struct { Label string SceneID id.SceneID + Parent *id.TagID LinkedDatasetSchemaID *id.DatasetSchemaID LinkedDatasetID *id.DatasetID LinkedDatasetField *id.DatasetSchemaFieldID @@ -46,14 +48,10 @@ type Tag interface { FetchByScene(context.Context, id.SceneID, *usecase.Operator) ([]*tag.Tag, error) FetchItem(context.Context, []id.TagID, *usecase.Operator) ([]*tag.Item, error) FetchGroup(context.Context, []id.TagID, *usecase.Operator) ([]*tag.Group, error) - FetchGroupsByLayer(context.Context, id.LayerID, *usecase.Operator) ([]*tag.Group, error) - FetchGroupsByScene(context.Context, id.SceneID, *usecase.Operator) ([]*tag.Group, error) - FetchItemsByLayer(context.Context, id.LayerID, *usecase.Operator) ([]*tag.Item, error) - FetchItemsByScene(context.Context, id.SceneID, *usecase.Operator) ([]*tag.Item, error) - CreateItem(context.Context, CreateTagItemParam, *usecase.Operator) (*tag.Item, error) + CreateItem(context.Context, CreateTagItemParam, *usecase.Operator) (*tag.Item, *tag.Group, error) CreateGroup(context.Context, CreateTagGroupParam, *usecase.Operator) (*tag.Group, error) AttachItemToGroup(context.Context, AttachItemToGroupParam, *usecase.Operator) (*tag.Group, error) DetachItemFromGroup(context.Context, DetachItemToGroupParam, *usecase.Operator) (*tag.Group, error) UpdateTag(context.Context, UpdateTagParam, *usecase.Operator) (*tag.Tag, error) - Remove(context.Context, id.TagID, *usecase.Operator) (*id.TagID, error) + Remove(context.Context, id.TagID, *usecase.Operator) (*id.TagID, layer.List, error) } diff --git a/internal/usecase/repo/tag.go b/internal/usecase/repo/tag.go index 2554989a..456642f7 100644 --- a/internal/usecase/repo/tag.go +++ b/internal/usecase/repo/tag.go @@ -14,10 +14,8 @@ type Tag interface { FindItemByIDs(context.Context, []id.TagID, []id.SceneID) ([]*tag.Item, error) FindGroupByID(context.Context, id.TagID, []id.SceneID) (*tag.Group, error) FindGroupByIDs(context.Context, []id.TagID, []id.SceneID) ([]*tag.Group, error) - FindByScene(context.Context, id.SceneID) ([]*tag.Tag, error) + FindRootsByScene(context.Context, id.SceneID) ([]*tag.Tag, error) FindGroupByItem(context.Context, id.TagID, []id.SceneID) (*tag.Group, error) - FindGroupByScene(context.Context, id.SceneID) ([]*tag.Group, error) - FindItemByScene(context.Context, id.SceneID) ([]*tag.Item, error) Save(context.Context, tag.Tag) error SaveAll(context.Context, []*tag.Tag) error Remove(context.Context, id.TagID) error diff --git a/pkg/layer/builder.go b/pkg/layer/builder.go index e28e2795..0eadb525 100644 --- a/pkg/layer/builder.go +++ b/pkg/layer/builder.go @@ -2,7 +2,6 @@ package layer import ( "github.com/reearth/reearth-backend/pkg/id" - "github.com/reearth/reearth-backend/pkg/tag" ) type Builder struct { @@ -73,7 +72,7 @@ func (b *Builder) Infobox(infobox *Infobox) *Builder { return b } -func (b *Builder) Tags(tags *tag.List) *Builder { +func (b *Builder) Tags(tags *TagList) *Builder { b.base.tags = tags return b } diff --git a/pkg/layer/group.go b/pkg/layer/group.go index e0728494..ca1a6c33 100644 --- a/pkg/layer/group.go +++ b/pkg/layer/group.go @@ -3,7 +3,6 @@ package layer import ( "github.com/reearth/reearth-backend/pkg/id" "github.com/reearth/reearth-backend/pkg/property" - "github.com/reearth/reearth-backend/pkg/tag" ) type Group struct { @@ -182,22 +181,9 @@ func (l *Group) ValidateProperties(pm property.Map) error { return l.layerBase.ValidateProperties(pm) } -func (l *Group) Tags() *tag.List { - return l.layerBase.tags -} - -func (l *Group) AttachTag(t id.TagID) error { - if l.layerBase.tags.Has(t) { - return ErrDuplicatedTag +func (l *Group) Tags() *TagList { + if l.layerBase.tags == nil { + l.layerBase.tags = NewTagList(nil) } - l.layerBase.tags.Add(t) - return nil -} - -func (l *Group) DetachTag(t id.TagID) error { - if !l.layerBase.tags.Has(t) { - return ErrTagNotFound - } - l.layerBase.tags.Remove(t) - return nil + return l.layerBase.tags } diff --git a/pkg/layer/group_builder.go b/pkg/layer/group_builder.go index 5c5e67dd..a271589c 100644 --- a/pkg/layer/group_builder.go +++ b/pkg/layer/group_builder.go @@ -2,7 +2,6 @@ package layer import ( "github.com/reearth/reearth-backend/pkg/id" - "github.com/reearth/reearth-backend/pkg/tag" ) func GroupFromLayer(l Layer) *Group { @@ -112,7 +111,7 @@ func (b *GroupBuilder) LinkedDatasetSchema(linkedDatasetSchema *id.DatasetSchema return b } -func (b *GroupBuilder) Tags(tags *tag.List) *GroupBuilder { +func (b *GroupBuilder) Tags(tags *TagList) *GroupBuilder { b.l.tags = tags return b } diff --git a/pkg/layer/group_builder_test.go b/pkg/layer/group_builder_test.go index 14194147..cd03a262 100644 --- a/pkg/layer/group_builder_test.go +++ b/pkg/layer/group_builder_test.go @@ -3,13 +3,11 @@ package layer import ( "testing" - "github.com/reearth/reearth-backend/pkg/id" - "github.com/reearth/reearth-backend/pkg/tag" "github.com/stretchr/testify/assert" ) func TestGroupBuilder_Tags(t *testing.T) { - l := tag.NewListFromTags([]id.TagID{id.NewTagID()}) + l := NewTagList(nil) b := NewGroup().NewID().Tags(l).MustBuild() assert.Same(t, l, b.Tags()) } diff --git a/pkg/layer/group_test.go b/pkg/layer/group_test.go index d4d3bea4..555d1f20 100644 --- a/pkg/layer/group_test.go +++ b/pkg/layer/group_test.go @@ -3,8 +3,6 @@ package layer import ( "testing" - "github.com/reearth/reearth-backend/pkg/tag" - "github.com/reearth/reearth-backend/pkg/id" "github.com/stretchr/testify/assert" ) @@ -13,7 +11,6 @@ var _ Layer = &Group{} var l1 = id.MustLayerID(id.New().String()) var l2 = id.MustLayerID(id.New().String()) -var tags = []id.TagID{id.NewTagID()} var group = Group{ layerBase: layerBase{ id: id.MustLayerID(id.New().String()), @@ -23,7 +20,7 @@ var group = Group{ extension: id.PluginExtensionID("foo").Ref(), property: nil, infobox: nil, - tags: tag.NewListFromTags(tags), + tags: nil, scene: id.SceneID{}, }, layers: &IDList{ @@ -139,15 +136,3 @@ func TestGroup_MoveLayerFrom(t *testing.T) { group.MoveLayerFrom(l1, 1, &group) assert.Equal(t, l1, group.Layers().Layers()[1]) } - -func TestGroup_Tags(t *testing.T) { - tt := id.NewTagID() - err := group.AttachTag(tt) - assert.NoError(t, err) - tl := tags - tl = append(tl, tt) - assert.Equal(t, tl, group.Tags().Tags()) - err = group.DetachTag(tt) - assert.NoError(t, err) - assert.Equal(t, tags, group.Tags().Tags()) -} diff --git a/pkg/layer/item.go b/pkg/layer/item.go index ca92a8c5..abf81999 100644 --- a/pkg/layer/item.go +++ b/pkg/layer/item.go @@ -3,7 +3,6 @@ package layer import ( "github.com/reearth/reearth-backend/pkg/id" "github.com/reearth/reearth-backend/pkg/property" - "github.com/reearth/reearth-backend/pkg/tag" ) type Item struct { @@ -151,22 +150,9 @@ func (l *Item) ValidateProperties(pm property.Map) error { return l.layerBase.ValidateProperties(pm) } -func (l *Item) Tags() *tag.List { - return l.layerBase.tags -} - -func (l *Item) AttachTag(t id.TagID) error { - if l.layerBase.tags.Has(t) { - return ErrDuplicatedTag +func (l *Item) Tags() *TagList { + if l.layerBase.tags == nil { + l.layerBase.tags = NewTagList(nil) } - l.layerBase.tags.Add(t) - return nil -} - -func (l *Item) DetachTag(t id.TagID) error { - if !l.layerBase.tags.Has(t) { - return ErrTagNotFound - } - l.layerBase.tags.Remove(t) - return nil + return l.layerBase.tags } diff --git a/pkg/layer/item_builder.go b/pkg/layer/item_builder.go index 68a66b21..c358af08 100644 --- a/pkg/layer/item_builder.go +++ b/pkg/layer/item_builder.go @@ -2,7 +2,6 @@ package layer import ( "github.com/reearth/reearth-backend/pkg/id" - "github.com/reearth/reearth-backend/pkg/tag" ) func ItemFromLayer(l Layer) *Item { @@ -102,7 +101,7 @@ func (b *ItemBuilder) LinkedDataset(linkedDataset *id.DatasetID) *ItemBuilder { return b } -func (b *ItemBuilder) Tags(tags *tag.List) *ItemBuilder { +func (b *ItemBuilder) Tags(tags *TagList) *ItemBuilder { b.l.tags = tags return b } diff --git a/pkg/layer/item_builder_test.go b/pkg/layer/item_builder_test.go index 2c76c6a2..4d83b01d 100644 --- a/pkg/layer/item_builder_test.go +++ b/pkg/layer/item_builder_test.go @@ -3,13 +3,11 @@ package layer import ( "testing" - "github.com/reearth/reearth-backend/pkg/id" - "github.com/reearth/reearth-backend/pkg/tag" "github.com/stretchr/testify/assert" ) func TestItemBuilder_Tags(t *testing.T) { - l := tag.NewListFromTags([]id.TagID{id.NewTagID()}) + l := NewTagList(nil) b := NewItem().NewID().Tags(l).MustBuild() assert.Same(t, l, b.Tags()) } diff --git a/pkg/layer/item_test.go b/pkg/layer/item_test.go index d65d9203..a803e2de 100644 --- a/pkg/layer/item_test.go +++ b/pkg/layer/item_test.go @@ -1,39 +1,3 @@ package layer -import ( - "testing" - - "github.com/reearth/reearth-backend/pkg/id" - "github.com/reearth/reearth-backend/pkg/tag" - "github.com/stretchr/testify/assert" -) - var _ Layer = &Item{} - -var tags2 = []id.TagID{id.NewTagID()} -var item = Item{ - layerBase: layerBase{ - id: id.MustLayerID(id.New().String()), - name: "xxx", - visible: false, - plugin: id.MustPluginID("aaa~1.1.1").Ref(), - extension: id.PluginExtensionID("foo").Ref(), - property: nil, - infobox: nil, - tags: tag.NewListFromTags(tags2), - scene: id.SceneID{}, - }, - linkedDataset: nil, -} - -func TestItem_Tags(t *testing.T) { - tt := id.NewTagID() - err := item.AttachTag(tt) - assert.NoError(t, err) - tl := tags2 - tl = append(tl, tt) - assert.Equal(t, tl, item.Tags().Tags()) - err = item.DetachTag(tt) - assert.NoError(t, err) - assert.Equal(t, tags2, item.Tags().Tags()) -} diff --git a/pkg/layer/layer.go b/pkg/layer/layer.go index 56013b29..86461c25 100644 --- a/pkg/layer/layer.go +++ b/pkg/layer/layer.go @@ -6,7 +6,6 @@ import ( "github.com/reearth/reearth-backend/pkg/id" "github.com/reearth/reearth-backend/pkg/property" - "github.com/reearth/reearth-backend/pkg/tag" ) var ( @@ -25,15 +24,13 @@ type Layer interface { HasInfobox() bool Infobox() *Infobox Scene() id.SceneID - Tags() *tag.List + Tags() *TagList Rename(string) SetVisible(bool) SetInfobox(*Infobox) SetPlugin(*id.PluginID) Properties() []id.PropertyID ValidateProperties(property.Map) error - AttachTag(t id.TagID) error - DetachTag(t id.TagID) error } func ToLayerGroup(l Layer) *Group { @@ -81,7 +78,7 @@ type layerBase struct { property *id.PropertyID infobox *Infobox scene id.SceneID - tags *tag.List + tags *TagList } func (l *layerBase) ID() id.LayerID { diff --git a/pkg/layer/tag.go b/pkg/layer/tag.go new file mode 100644 index 00000000..d3446473 --- /dev/null +++ b/pkg/layer/tag.go @@ -0,0 +1,226 @@ +package layer + +import "github.com/reearth/reearth-backend/pkg/id" + +type TagID = id.TagID + +var NewTagID = id.NewTagID + +type TagList struct { + tags []Tag +} + +type Tag interface { + ID() TagID + Clone() Tag +} + +type TagItem struct { + id TagID +} + +type TagGroup struct { + id TagID + children []*TagItem +} + +func NewTagItem(t TagID) *TagItem { + if t.IsNil() { + return nil + } + return &TagItem{ + id: t, + } +} + +func (t *TagItem) ID() TagID { + if t == nil { + return TagID{} + } + return t.id +} + +func TagItemFrom(t Tag) *TagItem { + t2, _ := t.(*TagItem) + return t2 +} + +func (t *TagItem) Clone() Tag { + return t.CloneItem() +} + +func (t *TagItem) CloneItem() *TagItem { + if t == nil { + return nil + } + return NewTagItem(t.id) +} + +func NewTagGroup(t TagID, children []*TagItem) *TagGroup { + if t.IsNil() { + return nil + } + return &TagGroup{ + id: t, + children: append(children[:0:0], children...), + } +} + +func TagGroupFrom(t Tag) *TagGroup { + t2, _ := t.(*TagGroup) + return t2 +} + +func (t *TagGroup) ID() TagID { + if t == nil { + return TagID{} + } + return t.id +} + +func (t *TagGroup) Children() []*TagItem { + if t == nil { + return nil + } + return append(t.children[:0:0], t.children...) +} + +func (t *TagGroup) Find(ti TagID) *TagItem { + if t == nil { + return nil + } + for _, tag := range t.children { + if tag.ID() == ti { + return tag + } + } + return nil +} + +func (t *TagGroup) Add(ti *TagItem) bool { + if t == nil || ti == nil || t.Find(ti.ID()) != nil { + return false + } + t.children = append(t.children, ti) + return true +} + +func (t *TagGroup) Delete(ti TagID) (res bool) { + if t == nil { + return + } + for i := 0; i < len(t.children); i++ { + c := t.children[i] + if c.ID() == ti { + t.children = append(t.children[:i], t.children[i+1:]...) + i-- + res = true + } + } + return +} + +func (t *TagGroup) Clone() Tag { + return t.CloneGroup() +} + +func (t *TagGroup) CloneGroup() *TagGroup { + if t == nil { + return nil + } + return NewTagGroup(t.id, t.children) +} + +func NewTagList(tags []Tag) *TagList { + return &TagList{tags: append(tags[:0:0], tags...)} +} + +func (t *TagList) Tags() []Tag { + if t == nil { + return nil + } + return append(t.tags[:0:0], t.tags...) +} + +func (t *TagList) Add(ti Tag) bool { + if t == nil || ti == nil || t.Has(ti.ID()) || TagItemFrom(ti) == nil && TagGroupFrom(ti) == nil { + return false + } + t.tags = append(t.tags, ti) + return true +} + +func (t *TagList) Delete(ti TagID) (res bool) { + if t == nil { + return + } + for i := 0; i < len(t.tags); i++ { + c := t.tags[i] + if c.ID() == ti { + t.tags = append(t.tags[:i], t.tags[i+1:]...) + i-- + res = true + } else if TagGroupFrom(c).Delete(ti) { + res = true + } + } + return +} + +func (t *TagList) Has(ti TagID) bool { + g, i := t.Find(ti) + return g != nil || i != nil +} + +func (t *TagList) Find(ti TagID) (*TagGroup, *TagItem) { + if t == nil { + return nil, nil + } + for _, t := range t.tags { + g := TagGroupFrom(t) + if t.ID() == ti { + return g, TagItemFrom(t) + } + if i := g.Find(ti); i != nil { + return g, i + } + } + return nil, nil +} + +func (t *TagList) FindItem(ti TagID) *TagItem { + _, i := t.Find(ti) + return i +} + +func (t *TagList) FindGroup(ti TagID) *TagGroup { + g, i := t.Find(ti) + if i != nil { + return nil + } + return g +} + +func (t *TagList) RootItems() []*TagItem { + if t == nil { + return nil + } + items := make([]*TagItem, 0, len(t.tags)) + for _, t := range t.tags { + if i := TagItemFrom(t); i != nil { + items = append(items, i) + } + } + return items +} + +func (t *TagList) IsEmpty() bool { + return t == nil || len(t.tags) == 0 +} + +func (t *TagList) Clone() *TagList { + if t == nil { + return nil + } + return NewTagList(t.tags) +} diff --git a/pkg/layer/tag_test.go b/pkg/layer/tag_test.go new file mode 100644 index 00000000..3768a2f2 --- /dev/null +++ b/pkg/layer/tag_test.go @@ -0,0 +1,1086 @@ +package layer + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +var _ Tag = &TagItem{} +var _ Tag = &TagGroup{} + +func TestNewTagItem(t *testing.T) { + tag := NewTagID() + type args struct { + t TagID + } + tests := []struct { + name string + args args + want *TagItem + }{ + { + name: "ok", + args: args{t: tag}, + want: &TagItem{id: tag}, + }, + { + name: "nil id", + args: args{t: TagID{}}, + want: nil, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, tt.want, NewTagItem(tt.args.t)) + }) + } +} + +func TestTagItemFrom(t *testing.T) { + tag := NewTagID() + type args struct { + t Tag + } + tests := []struct { + name string + args args + want *TagItem + }{ + { + name: "item", + args: args{t: &TagItem{id: tag}}, + want: &TagItem{id: tag}, + }, + { + name: "group", + args: args{t: &TagGroup{id: tag}}, + want: nil, + }, + { + name: "nil item", + args: args{t: (*TagItem)(nil)}, + want: nil, + }, + { + name: "nil group", + args: args{t: (*TagGroup)(nil)}, + want: nil, + }, + { + name: "nil", + args: args{t: nil}, + want: nil, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, tt.want, TagItemFrom(tt.args.t)) + }) + } +} + +func TestTagItem_ID(t *testing.T) { + tag := NewTagID() + tests := []struct { + name string + target *TagItem + want TagID + }{ + { + name: "ok", + target: &TagItem{id: tag}, + want: tag, + }, + { + name: "nil", + target: nil, + want: TagID{}, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, tt.want, tt.target.ID()) + }) + } +} + +func TestTagItem_Clone(t *testing.T) { + tag := NewTagID() + tests := []struct { + name string + target *TagItem + }{ + { + name: "ok", + target: &TagItem{id: tag}, + }, + { + name: "nil", + target: nil, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + res := tt.target.Clone() + assert.Equal(t, tt.target, res) + if tt.target != nil { + assert.NotSame(t, tt.target, res) + } + }) + } +} + +func TestTagItem_CloneItem(t *testing.T) { + tag := NewTagID() + tests := []struct { + name string + target *TagItem + }{ + { + name: "ok", + target: &TagItem{id: tag}, + }, + { + name: "nil", + target: nil, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + res := tt.target.CloneItem() + assert.Equal(t, tt.target, res) + if tt.target != nil { + assert.NotSame(t, tt.target, res) + } + }) + } +} + +func TestNewTagGroup(t *testing.T) { + tag1 := NewTagID() + tag2 := NewTagID() + tag3 := NewTagID() + + type args struct { + t TagID + children []*TagItem + } + tests := []struct { + name string + args args + want *TagGroup + }{ + { + name: "ok", + args: args{ + t: tag1, + children: []*TagItem{ + {id: tag2}, + {id: tag3}, + }, + }, + want: &TagGroup{ + id: tag1, + children: []*TagItem{ + {id: tag2}, + {id: tag3}, + }, + }, + }, + { + name: "nil id", + args: args{t: TagID{}}, + want: nil, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, tt.want, NewTagGroup(tt.args.t, tt.args.children)) + }) + } +} + +func TestTagGroupFrom(t *testing.T) { + tag := NewTagID() + type args struct { + t Tag + } + tests := []struct { + name string + args args + want *TagGroup + }{ + { + name: "group", + args: args{t: &TagGroup{id: tag}}, + want: &TagGroup{id: tag}, + }, + { + name: "item", + args: args{t: &TagItem{id: tag}}, + want: nil, + }, + { + name: "nil item", + args: args{t: (*TagItem)(nil)}, + want: nil, + }, + { + name: "nil group", + args: args{t: (*TagGroup)(nil)}, + want: nil, + }, + { + name: "nil", + args: args{t: nil}, + want: nil, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, tt.want, TagGroupFrom(tt.args.t)) + }) + } +} + +func TestTagGroup_ID(t *testing.T) { + tag := NewTagID() + tests := []struct { + name string + target *TagGroup + want TagID + }{ + { + name: "ok", + target: &TagGroup{id: tag}, + want: tag, + }, + { + name: "nil", + target: nil, + want: TagID{}, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, tt.want, tt.target.ID()) + }) + } +} + +func TestTagGroup_Children(t *testing.T) { + tag1 := NewTagID() + tag2 := NewTagID() + + tests := []struct { + name string + target *TagGroup + want []*TagItem + }{ + { + name: "ok", + target: &TagGroup{id: tag1, children: []*TagItem{{id: tag2}}}, + want: []*TagItem{{id: tag2}}, + }, + { + name: "nil", + target: nil, + want: nil, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + res := tt.target.Children() + assert.Equal(t, tt.want, res) + if tt.want != nil { + assert.NotSame(t, tt.target.children, res) + } + }) + } +} + +func TestTagGroup_Find(t *testing.T) { + tag1 := NewTagID() + tag2 := NewTagID() + tag3 := NewTagID() + + type args struct { + ti TagID + } + tests := []struct { + name string + target *TagGroup + args args + want *TagItem + }{ + { + name: "ok", + target: &TagGroup{id: tag1, children: []*TagItem{{id: tag2}, {id: tag3}}}, + args: args{ti: tag2}, + want: &TagItem{id: tag2}, + }, + { + name: "not found", + target: &TagGroup{id: tag1, children: []*TagItem{{id: tag2}, {id: tag3}}}, + args: args{ti: tag1}, + want: nil, + }, + { + name: "nil", + target: nil, + args: args{ti: tag1}, + want: nil, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + res := tt.target.Find(tt.args.ti) + assert.Equal(t, tt.want, res) + }) + } +} + +func TestTagGroup_Add(t *testing.T) { + tag1 := NewTagID() + tag2 := NewTagID() + tag3 := NewTagID() + + type args struct { + ti *TagItem + } + tests := []struct { + name string + target *TagGroup + args args + want bool + wantChildren []*TagItem + }{ + { + name: "ok", + target: &TagGroup{id: tag1, children: []*TagItem{{id: tag3}}}, + args: args{ti: &TagItem{id: tag2}}, + want: true, + wantChildren: []*TagItem{{id: tag3}, {id: tag2}}, + }, + { + name: "not added", + target: &TagGroup{id: tag1, children: []*TagItem{{id: tag2}, {id: tag3}}}, + args: args{ti: &TagItem{id: tag2}}, + want: false, + wantChildren: []*TagItem{{id: tag2}, {id: tag3}}, + }, + { + name: "nil item", + target: &TagGroup{id: tag1, children: []*TagItem{{id: tag2}}}, + args: args{ti: nil}, + wantChildren: []*TagItem{{id: tag2}}, + }, + { + name: "nil", + target: nil, + args: args{ti: &TagItem{id: tag2}}, + wantChildren: nil, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, tt.want, tt.target.Add(tt.args.ti)) + assert.Equal(t, tt.wantChildren, tt.target.Children()) + }) + } +} + +func TestTagGroup_Delete(t *testing.T) { + tag1 := NewTagID() + tag2 := NewTagID() + tag3 := NewTagID() + + type args struct { + ti TagID + } + tests := []struct { + name string + target *TagGroup + args args + want bool + wantChildren []*TagItem + }{ + { + name: "ok", + target: &TagGroup{id: tag1, children: []*TagItem{{id: tag2}, {id: tag3}}}, + args: args{ti: tag2}, + want: true, + wantChildren: []*TagItem{{id: tag3}}, + }, + { + name: "not found", + target: &TagGroup{id: tag1, children: []*TagItem{{id: tag2}, {id: tag3}}}, + args: args{ti: tag1}, + want: false, + wantChildren: []*TagItem{{id: tag2}, {id: tag3}}, + }, + { + name: "nil", + target: nil, + args: args{ti: tag1}, + wantChildren: nil, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, tt.want, tt.target.Delete(tt.args.ti)) + assert.Equal(t, tt.wantChildren, tt.target.Children()) + }) + } +} + +func TestTagGroup_Clone(t *testing.T) { + tag1 := NewTagID() + tag2 := NewTagID() + + tests := []struct { + name string + target *TagGroup + }{ + { + name: "ok", + target: &TagGroup{id: tag1, children: []*TagItem{{id: tag2}}}, + }, + { + name: "nil", + target: nil, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + res := tt.target.Clone() + assert.Equal(t, tt.target, res) + if tt.target != nil { + assert.NotSame(t, tt.target, res) + } + }) + } +} + +func TestTagGroup_CloneGroup(t *testing.T) { + tag1 := NewTagID() + tag2 := NewTagID() + + tests := []struct { + name string + target *TagGroup + }{ + { + name: "ok", + target: &TagGroup{id: tag1, children: []*TagItem{{id: tag2}}}, + }, + { + name: "nil", + target: nil, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + res := tt.target.CloneGroup() + assert.Equal(t, tt.target, res) + if tt.target != nil { + assert.NotSame(t, tt.target, res) + if tt.target.children != nil { + assert.NotSame(t, tt.target.children, res.children) + } + } + }) + } +} + +func TestNewTagList(t *testing.T) { + tag := NewTagID() + + type args struct { + tags []Tag + } + tests := []struct { + name string + args args + want *TagList + }{ + { + name: "ok", + args: args{tags: []Tag{&TagItem{id: tag}}}, + want: &TagList{tags: []Tag{&TagItem{id: tag}}}, + }, + { + name: "nil", + args: args{tags: nil}, + want: &TagList{tags: nil}, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + res := NewTagList(tt.args.tags) + assert.Equal(t, tt.want, res) + assert.NotSame(t, res.tags, tt.args.tags) + }) + } +} + +func TestTagList_Tags(t *testing.T) { + tag1 := NewTagID() + tag2 := NewTagID() + tag3 := NewTagID() + + tests := []struct { + name string + target *TagList + want []Tag + }{ + { + name: "ok", + target: &TagList{ + tags: []Tag{&TagGroup{id: tag1, children: []*TagItem{{id: tag2}}}, &TagItem{id: tag3}}, + }, + want: []Tag{&TagGroup{id: tag1, children: []*TagItem{{id: tag2}}}, &TagItem{id: tag3}}, + }, + { + name: "nil", + target: nil, + want: nil, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + res := tt.target.Tags() + assert.Equal(t, tt.want, res) + if tt.want != nil { + assert.NotSame(t, tt.target.tags, res) + } + }) + } +} + +func TestTagList_Add(t *testing.T) { + tag1 := NewTagID() + tag2 := NewTagID() + tag3 := NewTagID() + + type args struct { + ti Tag + } + tests := []struct { + name string + target *TagList + args args + want bool + wantChildren []Tag + }{ + { + name: "item added", + target: &TagList{ + tags: []Tag{ + &TagGroup{id: tag1, children: []*TagItem{{id: tag3}}}, + }, + }, + args: args{ti: &TagItem{id: tag2}}, + want: true, + wantChildren: []Tag{ + &TagGroup{id: tag1, children: []*TagItem{{id: tag3}}}, + &TagItem{id: tag2}, + }, + }, + { + name: "group added", + target: &TagList{ + tags: []Tag{ + &TagGroup{id: tag1, children: []*TagItem{{id: tag3}}}, + }, + }, + args: args{ti: &TagGroup{id: tag2}}, + want: true, + wantChildren: []Tag{ + &TagGroup{id: tag1, children: []*TagItem{{id: tag3}}}, + &TagGroup{id: tag2}, + }, + }, + { + name: "not added", + target: &TagList{ + tags: []Tag{&TagItem{id: tag2}, &TagGroup{id: tag1, children: []*TagItem{{id: tag3}}}}, + }, + args: args{ti: &TagGroup{id: tag2}}, + want: false, + wantChildren: []Tag{ + &TagItem{id: tag2}, + &TagGroup{id: tag1, children: []*TagItem{{id: tag3}}}, + }, + }, + { + name: "nil tag", + target: &TagList{ + tags: []Tag{&TagItem{id: tag2}, &TagGroup{id: tag1, children: []*TagItem{{id: tag3}}}}, + }, + args: args{ti: nil}, + want: false, + wantChildren: []Tag{&TagItem{id: tag2}, &TagGroup{id: tag1, children: []*TagItem{{id: tag3}}}}, + }, + { + name: "nil item tag", + target: &TagList{ + tags: []Tag{&TagItem{id: tag2}, &TagGroup{id: tag1, children: []*TagItem{{id: tag3}}}}, + }, + args: args{ti: (*TagItem)(nil)}, + want: false, + wantChildren: []Tag{&TagItem{id: tag2}, &TagGroup{id: tag1, children: []*TagItem{{id: tag3}}}}, + }, + { + name: "nil", + args: args{ti: &TagGroup{id: tag2}}, + target: nil, + wantChildren: nil, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, tt.want, tt.target.Add(tt.args.ti)) + assert.Equal(t, tt.wantChildren, tt.target.Tags()) + }) + } +} + +func TestTagList_Delete(t *testing.T) { + tag1 := NewTagID() + tag2 := NewTagID() + tag3 := NewTagID() + tag4 := NewTagID() + + type args struct { + ti TagID + } + tests := []struct { + name string + target *TagList + args args + want bool + wantTags []Tag + }{ + { + name: "ok", + target: &TagList{ + tags: []Tag{ + &TagItem{id: tag1}, + &TagGroup{id: tag2, children: []*TagItem{{id: tag3}}}, + }, + }, + args: args{ti: tag1}, + want: true, + wantTags: []Tag{ + &TagGroup{id: tag2, children: []*TagItem{{id: tag3}}}, + }, + }, + { + name: "not found", + target: &TagList{ + tags: []Tag{ + &TagItem{id: tag1}, + &TagGroup{id: tag2, children: []*TagItem{{id: tag3}}}, + }, + }, + args: args{ti: tag4}, + want: false, + wantTags: []Tag{ + &TagItem{id: tag1}, + &TagGroup{id: tag2, children: []*TagItem{{id: tag3}}}, + }, + }, + { + name: "nil", + target: nil, + args: args{ti: tag1}, + wantTags: nil, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, tt.want, tt.target.Delete(tt.args.ti)) + assert.Equal(t, tt.wantTags, tt.target.Tags()) + }) + } +} + +func TestTagList_Find(t *testing.T) { + tag1 := NewTagID() + tag2 := NewTagID() + tag3 := NewTagID() + tag4 := NewTagID() + + type args struct { + ti TagID + } + tests := []struct { + name string + target *TagList + args args + wantGroup *TagGroup + wantItem *TagItem + }{ + { + name: "group", + target: &TagList{ + tags: []Tag{ + &TagItem{id: tag1}, + &TagGroup{id: tag2, children: []*TagItem{{id: tag3}}}, + }, + }, + args: args{ti: tag2}, + wantGroup: &TagGroup{id: tag2, children: []*TagItem{{id: tag3}}}, + wantItem: nil, + }, + { + name: "item", + target: &TagList{ + tags: []Tag{ + &TagItem{id: tag1}, + &TagGroup{id: tag2, children: []*TagItem{{id: tag3}}}, + }, + }, + args: args{ti: tag3}, + wantGroup: &TagGroup{id: tag2, children: []*TagItem{{id: tag3}}}, + wantItem: &TagItem{id: tag3}, + }, + { + name: "root item", + target: &TagList{ + tags: []Tag{ + &TagItem{id: tag1}, + &TagGroup{id: tag2, children: []*TagItem{{id: tag3}}}, + }, + }, + args: args{ti: tag1}, + wantGroup: nil, + wantItem: &TagItem{id: tag1}, + }, + { + name: "not found", + target: &TagList{ + tags: []Tag{ + &TagItem{id: tag1}, + &TagGroup{id: tag2, children: []*TagItem{{id: tag3}}}, + }, + }, + args: args{ti: tag4}, + wantGroup: nil, + wantItem: nil, + }, + { + name: "nil", + target: nil, + args: args{ti: tag1}, + wantGroup: nil, + wantItem: nil, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + resGroup, resItem := tt.target.Find(tt.args.ti) + assert.Equal(t, tt.wantGroup, resGroup) + assert.Equal(t, tt.wantItem, resItem) + }) + } +} + +func TestTagList_FindGroup(t *testing.T) { + tag1 := NewTagID() + tag2 := NewTagID() + tag3 := NewTagID() + + type args struct { + ti TagID + } + tests := []struct { + name string + target *TagList + args args + want *TagGroup + }{ + { + name: "ok", + target: &TagList{ + tags: []Tag{ + &TagItem{id: tag1}, + &TagGroup{id: tag2, children: []*TagItem{{id: tag3}}}, + }, + }, + args: args{ti: tag2}, + want: &TagGroup{id: tag2, children: []*TagItem{{id: tag3}}}, + }, + { + name: "not found", + target: &TagList{ + tags: []Tag{ + &TagItem{id: tag1}, + &TagGroup{id: tag2, children: []*TagItem{{id: tag3}}}, + }, + }, + args: args{ti: tag1}, + want: nil, + }, + { + name: "nil", + target: nil, + args: args{ti: tag1}, + want: nil, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, tt.want, tt.target.FindGroup(tt.args.ti)) + }) + } +} + +func TestTagList_FindItem(t *testing.T) { + tag1 := NewTagID() + tag2 := NewTagID() + tag3 := NewTagID() + + type args struct { + ti TagID + } + tests := []struct { + name string + target *TagList + args args + want *TagItem + }{ + { + name: "ok", + target: &TagList{ + tags: []Tag{ + &TagItem{id: tag1}, + &TagGroup{id: tag2, children: []*TagItem{{id: tag3}}}, + }, + }, + args: args{ti: tag3}, + want: &TagItem{id: tag3}, + }, + { + name: "root item", + target: &TagList{ + tags: []Tag{ + &TagItem{id: tag1}, + &TagGroup{id: tag2, children: []*TagItem{{id: tag3}}}, + }, + }, + args: args{ti: tag1}, + want: &TagItem{id: tag1}, + }, + { + name: "not found", + target: &TagList{ + tags: []Tag{ + &TagItem{id: tag1}, + &TagGroup{id: tag2, children: []*TagItem{{id: tag3}}}, + }, + }, + args: args{ti: tag2}, + want: nil, + }, + { + name: "nil", + target: nil, + args: args{ti: tag1}, + want: nil, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, tt.want, tt.target.FindItem(tt.args.ti)) + }) + } +} + +func TestTagList_RootItems(t *testing.T) { + tag1 := NewTagID() + tag2 := NewTagID() + tag3 := NewTagID() + + tests := []struct { + name string + target *TagList + want []*TagItem + }{ + { + name: "ok", + target: &TagList{ + tags: []Tag{ + &TagItem{id: tag1}, + &TagGroup{id: tag2, children: []*TagItem{{id: tag3}}}, + }, + }, + want: []*TagItem{{id: tag1}}, + }, + { + name: "no roots", + target: &TagList{ + tags: []Tag{ + &TagGroup{id: tag2, children: []*TagItem{{id: tag3}}}, + }, + }, + want: []*TagItem{}, + }, + { + name: "empty", + target: &TagList{}, + want: []*TagItem{}, + }, + { + name: "nil", + target: nil, + want: nil, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, tt.want, tt.target.RootItems()) + }) + } +} + +func TestTagList_IsEmpty(t *testing.T) { + tag := NewTagID() + + tests := []struct { + name string + target *TagList + want bool + }{ + { + name: "ok", + target: &TagList{ + tags: []Tag{&TagItem{id: tag}}, + }, + want: false, + }, + { + name: "empty", + target: &TagList{}, + want: true, + }, + { + name: "nil", + target: nil, + want: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, tt.want, tt.target.IsEmpty()) + }) + } +} + +func TestTagList_Clone(t *testing.T) { + tag1 := NewTagID() + tag2 := NewTagID() + tag3 := NewTagID() + + tests := []struct { + name string + target *TagList + }{ + { + name: "ok", + target: &TagList{ + tags: []Tag{ + &TagItem{id: tag1}, + &TagGroup{id: tag2, children: []*TagItem{{id: tag3}}}, + }, + }, + }, + { + name: "nil", + target: nil, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + res := tt.target.Clone() + assert.Equal(t, tt.target, res) + if tt.target != nil { + assert.NotSame(t, tt.target, res) + } + }) + } +} diff --git a/pkg/tag/item.go b/pkg/tag/item.go index ee817289..efefa027 100644 --- a/pkg/tag/item.go +++ b/pkg/tag/item.go @@ -4,11 +4,16 @@ import "github.com/reearth/reearth-backend/pkg/id" type Item struct { tag + parent *id.TagID linkedDatasetFieldID *id.DatasetSchemaFieldID linkedDatasetID *id.DatasetID linkedDatasetSchemaID *id.DatasetSchemaID } +func (i *Item) Parent() *id.TagID { + return i.parent.CopyRef() +} + func (i *Item) LinkedDatasetFieldID() *id.DatasetSchemaFieldID { return i.linkedDatasetFieldID.CopyRef() } @@ -20,3 +25,10 @@ func (i *Item) LinkedDatasetID() *id.DatasetID { func (i *Item) LinkedDatasetSchemaID() *id.DatasetSchemaID { return i.linkedDatasetSchemaID.CopyRef() } + +func (i *Item) SetParent(p *id.TagID) { + if i == nil { + return + } + i.parent = p.CopyRef() +} diff --git a/pkg/tag/item_builder.go b/pkg/tag/item_builder.go index 6fb0dbde..4d2cb79a 100644 --- a/pkg/tag/item_builder.go +++ b/pkg/tag/item_builder.go @@ -51,6 +51,11 @@ func (b *ItemBuilder) Scene(sid id.SceneID) *ItemBuilder { return b } +func (b *ItemBuilder) Parent(p *id.TagID) *ItemBuilder { + b.i.parent = p.CopyRef() + return b +} + func (b *ItemBuilder) LinkedDatasetFieldID(dfid *id.DatasetSchemaFieldID) *ItemBuilder { b.i.linkedDatasetFieldID = dfid return b diff --git a/schema.graphql b/schema.graphql index 746cc817..bd8c8805 100644 --- a/schema.graphql +++ b/schema.graphql @@ -318,7 +318,6 @@ enum PluginExtensionType { INFOBOX } - type PluginExtension { extensionId: PluginExtensionID! pluginId: PluginID! @@ -660,12 +659,9 @@ interface Layer { plugin: Plugin extension: PluginExtension scenePlugin: ScenePlugin - tagIds: [ID!]! - tags: [Tag!]! @goField(forceResolver: true) + tags: [LayerTag!]! } -union Layers = LayerItem | LayerGroup - enum LayerEncodingFormat { KML CZML @@ -686,6 +682,7 @@ type LayerItem implements Layer { # parentId will not be always set parentId: ID linkedDatasetId: ID + tags: [LayerTag!]! parent: LayerGroup @goField(forceResolver: true) property: Property @goField(forceResolver: true) plugin: Plugin @goField(forceResolver: true) @@ -694,8 +691,6 @@ type LayerItem implements Layer { merged: MergedLayer @goField(forceResolver: true) scene: Scene @goField(forceResolver: true) scenePlugin: ScenePlugin @goField(forceResolver: true) - tagIds: [ID!]! - tags: [Tag!]! @goField(forceResolver: true) } type LayerGroup implements Layer { @@ -712,6 +707,7 @@ type LayerGroup implements Layer { linkedDatasetSchemaId: ID root: Boolean! layerIds: [ID!]! + tags: [LayerTag!]! parent: LayerGroup @goField(forceResolver: true) property: Property @goField(forceResolver: true) plugin: Plugin @goField(forceResolver: true) @@ -720,8 +716,6 @@ type LayerGroup implements Layer { layers: [Layer]! @goField(forceResolver: true) scene: Scene @goField(forceResolver: true) scenePlugin: ScenePlugin @goField(forceResolver: true) - tagIds: [ID!]! - tags: [Tag!]! @goField(forceResolver: true) } type Infobox { @@ -756,6 +750,22 @@ type InfoboxField { scenePlugin: ScenePlugin @goField(forceResolver: true) } +interface LayerTag { + tagId: ID! + tag: Tag +} + +type LayerTagItem implements LayerTag { + tagId: ID! + tag: Tag @goField(forceResolver: true) +} + +type LayerTagGroup implements LayerTag { + tagId: ID! + children: [LayerTagItem!]! + tag: Tag @goField(forceResolver: true) +} + type MergedLayer { originalId: ID! parentId: ID @@ -790,29 +800,34 @@ interface Tag { id: ID! sceneId: ID! label: String! + layers: [Layer!]! @goField(forceResolver: true) } type TagItem implements Tag { id: ID! sceneId: ID! label: String! + parentId: ID linkedDatasetID: ID linkedDatasetSchemaID: ID linkedDatasetFieldID: ID linkedDatasetSchema: DatasetSchema @goField(forceResolver: true) linkedDataset: Dataset @goField(forceResolver: true) linkedDatasetField: DatasetField @goField(forceResolver: true) + parent: TagGroup @goField(forceResolver: true) + layers: [Layer!]! @goField(forceResolver: true) } type TagGroup implements Tag { id: ID! sceneId: ID! label: String! - tags: [ID!] + tagIds: [ID!] + tags: [TagItem!]! @goField(forceResolver: true) + scene: Scene @goField(forceResolver: true) + layers: [Layer!]! @goField(forceResolver: true) } -union Tags = TagItem | TagGroup - type Cluster { id: ID! name: String! @@ -1176,6 +1191,7 @@ input AddDatasetSchemaInput { input CreateTagItemInput { sceneId: ID! label: String! + parent: ID linkedDatasetSchemaID: ID linkedDatasetID: ID linkedDatasetField: ID @@ -1435,6 +1451,7 @@ type AddDatasetSchemaPayload { type CreateTagItemPayload { tag: TagItem! + parent: TagGroup } type CreateTagGroupPayload { @@ -1453,16 +1470,17 @@ type UpdateTagPayload { tag: Tag! } -type AttachTagToLayerPayload{ +type AttachTagToLayerPayload { layer: Layer! } -type DetachTagFromLayerPayload{ +type DetachTagFromLayerPayload { layer: Layer! } -type RemoveTagPayload{ +type RemoveTagPayload { tagId: ID! + updatedLayers: [Layer!]! } type AddClusterPayload { @@ -1475,7 +1493,7 @@ type UpdateClusterPayload { cluster: Cluster! } -type RemoveClusterPayload{ +type RemoveClusterPayload { scene: Scene! clusterId: ID! } @@ -1611,7 +1629,9 @@ type Mutation { createScene(input: CreateSceneInput!): CreateScenePayload addWidget(input: AddWidgetInput!): AddWidgetPayload updateWidget(input: UpdateWidgetInput!): UpdateWidgetPayload - updateWidgetAlignSystem(input: UpdateWidgetAlignSystemInput!): UpdateWidgetAlignSystemPayload + updateWidgetAlignSystem( + input: UpdateWidgetAlignSystemInput! + ): UpdateWidgetAlignSystemPayload removeWidget(input: RemoveWidgetInput!): RemoveWidgetPayload installPlugin(input: InstallPluginInput!): InstallPluginPayload uninstallPlugin(input: UninstallPluginInput!): UninstallPluginPayload @@ -1634,7 +1654,9 @@ type Mutation { input: RemoveDatasetSchemaInput! ): RemoveDatasetSchemaPayload importDataset(input: ImportDatasetInput!): ImportDatasetPayload - importDatasetFromGoogleSheet(input: ImportDatasetFromGoogleSheetInput!): ImportDatasetPayload + importDatasetFromGoogleSheet( + input: ImportDatasetFromGoogleSheetInput! + ): ImportDatasetPayload addDatasetSchema(input: AddDatasetSchemaInput!): AddDatasetSchemaPayload # Property @@ -1668,8 +1690,12 @@ type Mutation { # Tag createTagItem(input: CreateTagItemInput!): CreateTagItemPayload createTagGroup(input: CreateTagGroupInput!): CreateTagGroupPayload - attachTagItemToGroup(input: AttachTagItemToGroupInput!): AttachTagItemToGroupPayload - detachTagItemFromGroup(input: DetachTagItemFromGroupInput!): DetachTagItemFromGroupPayload + attachTagItemToGroup( + input: AttachTagItemToGroupInput! + ): AttachTagItemToGroupPayload + detachTagItemFromGroup( + input: DetachTagItemFromGroupInput! + ): DetachTagItemFromGroupPayload updateTag(input: UpdateTagInput!): UpdateTagPayload removeTag(input: RemoveTagInput!): RemoveTagPayload }