pkg/query/logical/schema.go (119 lines of code) (raw):

// Licensed to Apache Software Foundation (ASF) under one or more contributor // license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright // ownership. Apache Software Foundation (ASF) licenses this file to you under // the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. package logical import ( "github.com/pkg/errors" databasev1 "github.com/apache/skywalking-banyandb/api/proto/banyandb/database/v1" "github.com/apache/skywalking-banyandb/banyand/tsdb" ) // IndexChecker allows checking the existence of a specific index rule. type IndexChecker interface { IndexDefined(tagName string) (bool, *databasev1.IndexRule) IndexRuleDefined(ruleName string) (bool, *databasev1.IndexRule) } type emptyIndexChecker struct{} func (emptyIndexChecker) IndexDefined(_ string) (bool, *databasev1.IndexRule) { return false, nil } func (emptyIndexChecker) IndexRuleDefined(_ string) (bool, *databasev1.IndexRule) { return false, nil } // TagSpecRegistry enables to find TagSpec by its name. type TagSpecRegistry interface { FindTagSpecByName(string) *TagSpec } // Schema allows retrieving schemas in a convenient way. type Schema interface { TagSpecRegistry IndexChecker Scope() tsdb.Entry EntityList() []string CreateTagRef(tags ...[]*Tag) ([][]*TagRef, error) CreateFieldRef(fields ...*Field) ([]*FieldRef, error) ProjTags(refs ...[]*TagRef) Schema ProjFields(refs ...*FieldRef) Schema Equal(Schema) bool } // TagSpec wraps offsets to access a tag in the raw data swiftly. type TagSpec struct { Spec *databasev1.TagSpec TagFamilyIdx int TagIdx int } // Equal compares fs and other have the same fields. func (fs *TagSpec) Equal(other *TagSpec) bool { return fs.TagFamilyIdx == other.TagFamilyIdx && fs.TagIdx == other.TagIdx && fs.Spec.GetType() == other.Spec.GetType() && fs.Spec.GetName() == other.Spec.GetName() } // TagSpecMap is a map of TapSpec implements TagSpecRegistry. type TagSpecMap map[string]*TagSpec // FindTagSpecByName finds TagSpec by its name in the registry. func (tagSpecMap TagSpecMap) FindTagSpecByName(name string) *TagSpec { if spec, ok := tagSpecMap[name]; ok { return spec } return nil } // RegisterTagFamilies registers the tag specs with a given slice of TagFamilySpec. func (tagSpecMap TagSpecMap) RegisterTagFamilies(tagFamilies []*databasev1.TagFamilySpec) { for tagFamilyIdx, tagFamily := range tagFamilies { for tagIdx, spec := range tagFamily.GetTags() { tagSpecMap.RegisterTag(tagFamilyIdx, tagIdx, spec) } } } // RegisterTag registers the tag spec with given tagFamilyName, tagName and indexes. func (tagSpecMap TagSpecMap) RegisterTag(tagFamilyIdx, tagIdx int, spec *databasev1.TagSpec) { tagSpecMap[spec.GetName()] = &TagSpec{ TagIdx: tagIdx, TagFamilyIdx: tagFamilyIdx, Spec: spec, } } // CommonSchema represents a sharable fields between independent schemas. // It provides common access methods at the same time. type CommonSchema struct { TagSpecMap IndexRules []*databasev1.IndexRule EntityList []string } // ProjTags inits a dictionary for getting TagSpec by tag's name. func (cs *CommonSchema) ProjTags(refs ...[]*TagRef) *CommonSchema { if len(refs) == 0 { return nil } newCommonSchema := &CommonSchema{ IndexRules: cs.IndexRules, TagSpecMap: make(map[string]*TagSpec), EntityList: cs.EntityList, } for projFamilyIdx, refInFamily := range refs { for projIdx, ref := range refInFamily { newCommonSchema.TagSpecMap[ref.Tag.getTagName()] = &TagSpec{ TagFamilyIdx: projFamilyIdx, TagIdx: projIdx, Spec: ref.Spec.Spec, } } } return newCommonSchema } // IndexDefined checks whether the field given is indexed. func (cs *CommonSchema) IndexDefined(tagName string) (bool, *databasev1.IndexRule) { for _, idxRule := range cs.IndexRules { for _, tn := range idxRule.GetTags() { if tn == tagName { return true, idxRule } } } return false, nil } // IndexRuleDefined return the IndexRule by its name. func (cs *CommonSchema) IndexRuleDefined(indexRuleName string) (bool, *databasev1.IndexRule) { for _, idxRule := range cs.IndexRules { if idxRule.GetMetadata().GetName() == indexRuleName { return true, idxRule } } return false, nil } // CreateRef create TagRef to the given tags. // The family name of the tag is actually not used // since the uniqueness of the tag names can be guaranteed across families. func (cs *CommonSchema) CreateRef(tags ...[]*Tag) ([][]*TagRef, error) { tagRefs := make([][]*TagRef, len(tags)) for i, tagInFamily := range tags { var tagRefsInFamily []*TagRef for _, tag := range tagInFamily { if ts, ok := cs.TagSpecMap[tag.getTagName()]; ok { tagRefsInFamily = append(tagRefsInFamily, &TagRef{tag, ts}) } else { return nil, errors.Wrap(errTagNotDefined, tag.GetCompoundName()) } } tagRefs[i] = tagRefsInFamily } return tagRefs, nil }