func Version(ctx context.Context, contentType string, condition db.Condition) (contenttype.Version, contenttype.ContentTyper, error) {
	_, err := definition.GetDefinition(contentType)
	if err != nil {
		return contenttype.Version{}, nil, err
	}
	version := contenttype.Version{}
	_, err = db.BindEntity(ctx, &version, "dm_version", condition.Cond("content_type", contentType))
	if err != nil {
		return contenttype.Version{}, nil, err
	}
	if version.ID == 0 {
		return contenttype.Version{}, nil, nil
	}
	data := []byte(version.Data)
	content := contenttype.NewInstance(contentType)
	author := version.Author
	err = json.Unmarshal(data, &content)
	if err != nil {
		return version, nil, errors.New("Not valid data for content")
	}
	content.SetValue("author", author)
	return version, content, nil
}
return a version content
package query
import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"strings"
	"github.com/digimakergo/digimaker/core/contenttype"
	"github.com/digimakergo/digimaker/core/db"
	"github.com/digimakergo/digimaker/core/definition"
	"github.com/digimakergo/digimaker/core/fieldtype"
	"github.com/digimakergo/digimaker/core/permission"
	"github.com/digimakergo/digimaker/core/util"
)
type TreeNode struct {
	*contenttype.Location
	Fields   interface{}              `json:"fields"`  
	Content  contenttype.ContentTyper `json:"content"`
	Children []TreeNode               `json:"children"`
}
func (tn *TreeNode) Iterate(operation func(node *TreeNode)) {
	operation(tn)
	for i, child := range tn.Children {
		child.Iterate(operation)
		tn.Children[i] = child
	}
}
func FetchByID(ctx context.Context, locationID int) (contenttype.ContentTyper, error) {
	location := contenttype.Location{}
	_, err := db.BindEntity(ctx, &location, "dm_location", db.Cond("id", locationID))
	if err != nil {
		return nil, fmt.Errorf("[contentquery.fetchbyid]Can not fetch location by locationID %v: %w", locationID, err)
	}
	if location.ID == 0 {
		return nil, errors.New("[contentquery.fetchbyid]Location is empty.")
	}
	contentID := location.ContentID
	contentType := location.ContentType
	result, err := FetchByCID(ctx, contentType, contentID)
	return result, err
}
func FetchByPath(ctx context.Context, path string) (contenttype.ContentTyper, error) {
	location := contenttype.Location{}
	_, err := db.BindEntity(ctx, &location, "dm_location", db.Cond("identifier_path", path))
	if err != nil {
		return nil, fmt.Errorf("[contentquery.fetchbypath]Can not fetch location by location path %v: %w", path, err)
	}
	if location.ID == 0 {
		return nil, errors.New("[contentquery.fetchbypath]Location is empty.")
	}
	contentID := location.ContentID
	contentType := location.ContentType
	result, err := FetchByCID(ctx, contentType, contentID)
	return result, err
}
func FetchByUID(ctx context.Context, uid string) (contenttype.ContentTyper, error) {
	location := contenttype.Location{}
	_, err := db.BindEntity(ctx, &location, "dm_location", db.Cond("uid", uid))
	if err != nil {
		return nil, fmt.Errorf("[contentquery.fetchbyuid]Can not fetch location by uid %v: %w", uid, err)
	}
	if location.ID == 0 {
		return nil, errors.New("[contentquery.fetchbyid]Location is empty.")
	}
	contentID := location.ContentID
	contentType := location.ContentType
	result, err := FetchByCID(ctx, contentType, contentID)
	return result, err
}
func FetchByCID(ctx context.Context, contentType string, contentID int) (contenttype.ContentTyper, error) {
	return Fetch(ctx, contentType, db.Cond("c.id", contentID))
}
func FetchByCUID(ctx context.Context, contentType string, cuid string) (contenttype.ContentTyper, error) {
	return Fetch(ctx, contentType, db.Cond("c.cuid", cuid))
}
func Fetch(ctx context.Context, contentType string, condition db.Condition) (contenttype.ContentTyper, error) {
	return DefaultQuerier.Fetch(ctx, contentType, condition)
}
func LocationList(condition db.Condition) ([]contenttype.Location, int, error) {
	locations := []contenttype.Location{}
	count, err := db.BindEntity(context.Background(), &locations, "dm_location", condition)
	if err != nil {
		return locations, 0, err
	}
	return locations, count, nil
}
func Children(ctx context.Context, userID int, parentContent contenttype.ContentTyper, contenttype string, cond db.Condition) ([]contenttype.ContentTyper, int, error) {
	contentTypeList := parentContent.Definition().AllowedTypes
	if !util.Contains(contentTypeList, contenttype) {
		return nil, -1, errors.New("content type " + contenttype + "doesn't exist or not allowed.")
	}
	result, countResult, err := SubList(ctx, userID, parentContent, contenttype, 1, cond)
	return result, countResult, err
}
func SubTree(ctx context.Context, userID int, rootContent contenttype.ContentTyper, depth int, contentTypes string, sortby []string) (TreeNode, error) {
	contentTypeList := strings.Split(contentTypes, ",")
	var list []contenttype.ContentTyper
	for _, contentType := range contentTypeList {
		currentList, _, err := SubList(ctx, userID, rootContent, contentType, depth, db.EmptyCond().Sortby(sortby...))
		if err != nil {
			return TreeNode{}, err
		}
		for _, item := range currentList {
			list = append(list, item)
		}
	}
	treenode := TreeNode{Content: rootContent, Location: rootContent.GetLocation()}
	buildTree(&treenode, list)
	return treenode, nil
}
func buildTree(treenode *TreeNode, list []contenttype.ContentTyper) {
	parentLocation := treenode.Content.GetLocation()
	for _, item := range list {
		location := item.GetLocation()
		if location.Depth == parentLocation.Depth+1 && location.ParentID == parentLocation.ID {
			treenode.Children = append(treenode.Children, TreeNode{Content: item, Location: location})
		}
	}
	for i, _ := range treenode.Children {
		buildTree(&treenode.Children[i], list)
	}
}
func accessCondition(userID int, contenttype string, context context.Context) db.Condition {
	accessType, limits, err := permission.GetUserAccess(context, userID, "content/read")
	if err != nil {
	}
	if accessType == permission.AccessNo {
		return db.FalseCond()
	}
	if accessType == permission.AccessFull {
		return db.EmptyCond()
	}
	result := db.EmptyCond()
	for _, limit := range limits {
		if ctype, ok := limit["contenttype"]; ok {
			ctypeList := ctype.([]interface{})
			ctypeMatched := false
			for _, value := range ctypeList {
				if value.(string) == contenttype {
					ctypeMatched = true
					break
				}
			}
			if !ctypeMatched {
				continue
			}
		}
		currentCond := db.EmptyCond()
		if section, ok := limit["section"]; ok {
			currentCond = currentCond.Cond("l.section", util.InterfaceToStringArray(section.([]interface{})))
		}
		if author, ok := limit["author"]; ok {
			if author.(string) == "self" {
				currentCond = currentCond.Cond("author", userID)
			}
		}
		result = result.Or(currentCond)
	}
	return result
}
func SubList(ctx context.Context, userID int, rootContent contenttype.ContentTyper, contentType string, depth int, condition db.Condition) ([]contenttype.ContentTyper, int, error) {
	rootLocation := rootContent.GetLocation()
	def, _ := definition.GetDefinition(contentType)
	if def.HasLocation {
		if depth == 1 {
			condition = condition.Cond("l.parent_id", rootLocation.ID)
		} else {
			rootHierarchy := rootLocation.Hierarchy
			rootDepth := rootLocation.Depth
			condition = condition.Cond("l.hierarchy like", rootHierarchy+"/%")
			if depth > 0 {
				condition = condition.Cond("l.depth <=", rootDepth+depth)
			}
		}
	} else {
		if def.HasDataField("location_id") {
			condition = condition.Cond("location_id", rootLocation.ID)
		}
	}
	list, count, err := ListWithUser(ctx, userID, contentType, condition)
	return list, count, err
}
func ListWithUser(ctx context.Context, userID int, contentType string, condition db.Condition) ([]contenttype.ContentTyper, int, error) {
	return DefaultQuerier.ListWithUser(ctx, userID, contentType, condition)
}
func List(ctx context.Context, contentType string, condition db.Condition) ([]contenttype.ContentTyper, int, error) {
	return DefaultQuerier.List(ctx, contentType, condition)
}