github.com/cayleygraph/cayley@v0.7.7/query/mql/fill.go (about)

     1  // Copyright 2014 The Cayley Authors. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package mql
    16  
    17  import (
    18  	"fmt"
    19  	"sort"
    20  
    21  	"github.com/cayleygraph/cayley/graph"
    22  	"github.com/cayleygraph/quad"
    23  )
    24  
    25  func (q *Query) treeifyResult(tags map[string]graph.Ref) map[ResultPath]string {
    26  	// Transform the map into something a little more interesting.
    27  	results := make(map[Path]string)
    28  	for k, v := range tags {
    29  		if v == nil {
    30  			continue
    31  		}
    32  		results[Path(k)] = quadValueToNative(q.ses.qs.NameOf(v))
    33  	}
    34  	resultPaths := make(map[ResultPath]string)
    35  	for k, v := range results {
    36  		resultPaths[k.ToResultPathFromMap(results)] = v
    37  	}
    38  
    39  	paths := make([]ResultPath, 0, len(resultPaths))
    40  	for path := range resultPaths {
    41  		paths = append(paths, path)
    42  	}
    43  	sort.Sort(byRecordLength(paths))
    44  
    45  	// Build Structure
    46  	for _, path := range paths {
    47  		currentPath := path.getPath()
    48  		value := resultPaths[path]
    49  		namePath := path.AppendValue(value)
    50  		if _, ok := q.queryResult[namePath]; !ok {
    51  			targetPath, key := path.splitLastPath()
    52  			if path == "" {
    53  				targetPath, key = "", value
    54  				if _, ok := q.queryResult[""][value]; !ok {
    55  					q.resultOrder = append(q.resultOrder, value)
    56  				}
    57  			}
    58  			if _, ok := q.queryStructure[currentPath]; ok {
    59  				// If there's substructure, then copy that in.
    60  				newStruct := q.copyPathStructure(currentPath)
    61  				if q.isRepeated[currentPath] && currentPath != "" {
    62  					switch t := q.queryResult[targetPath][key].(type) {
    63  					case nil:
    64  						x := make([]interface{}, 0)
    65  						x = append(x, newStruct)
    66  						q.queryResult[targetPath][key] = x
    67  						q.queryResult[namePath] = newStruct
    68  					case []interface{}:
    69  						q.queryResult[targetPath][key] = append(t, newStruct)
    70  						q.queryResult[namePath] = newStruct
    71  					}
    72  
    73  				} else {
    74  					q.queryResult[namePath] = newStruct
    75  					q.queryResult[targetPath][key] = newStruct
    76  				}
    77  			}
    78  		}
    79  	}
    80  
    81  	// Fill values
    82  	for _, path := range paths {
    83  		currentPath := path.getPath()
    84  		value, ok := resultPaths[path]
    85  		if !ok {
    86  			continue
    87  		}
    88  		namePath := path.AppendValue(value)
    89  		if _, ok := q.queryStructure[currentPath]; ok {
    90  			// We're dealing with ids.
    91  			if _, ok := q.queryResult[namePath]["id"]; ok {
    92  				q.queryResult[namePath]["id"] = value
    93  			}
    94  		} else {
    95  			// Just a value.
    96  			targetPath, key := path.splitLastPath()
    97  			if q.isRepeated[currentPath] {
    98  				switch t := q.queryResult[targetPath][key].(type) {
    99  				case nil:
   100  					x := make([]interface{}, 0)
   101  					x = append(x, value)
   102  					q.queryResult[targetPath][key] = x
   103  				case []interface{}:
   104  					q.queryResult[targetPath][key] = append(t, value)
   105  				}
   106  
   107  			} else {
   108  				q.queryResult[targetPath][key] = value
   109  			}
   110  		}
   111  	}
   112  
   113  	return resultPaths
   114  }
   115  
   116  func (q *Query) buildResults() {
   117  	for _, v := range q.resultOrder {
   118  		q.results = append(q.results, q.queryResult[""][v])
   119  	}
   120  }
   121  
   122  func quadValueToNative(v quad.Value) string {
   123  	out := quad.NativeOf(v)
   124  	if nv, ok := out.(quad.Value); ok && v == nv {
   125  		return quad.StringOf(v)
   126  	}
   127  	return fmt.Sprint(out)
   128  }