| 793 | } |
| 794 | |
| 795 | func (c *CompoundMultiIndex) FromObject(raw interface{}) (bool, [][]byte, error) { |
| 796 | // At each entry, builder is storing the results from the next index |
| 797 | builder := make([][][]byte, 0, len(c.Indexes)) |
| 798 | |
| 799 | forloop: |
| 800 | // This loop goes through each indexer and adds the value(s) provided to the next |
| 801 | // entry in the slice. We can then later walk it like a tree to construct the indices. |
| 802 | for i, idxRaw := range c.Indexes { |
| 803 | switch idx := idxRaw.(type) { |
| 804 | case SingleIndexer: |
| 805 | ok, val, err := idx.FromObject(raw) |
| 806 | if err != nil { |
| 807 | return false, nil, fmt.Errorf("single sub-index %d error: %v", i, err) |
| 808 | } |
| 809 | if !ok { |
| 810 | if c.AllowMissing { |
| 811 | break forloop |
| 812 | } else { |
| 813 | return false, nil, nil |
| 814 | } |
| 815 | } |
| 816 | builder = append(builder, [][]byte{val}) |
| 817 | |
| 818 | case MultiIndexer: |
| 819 | ok, vals, err := idx.FromObject(raw) |
| 820 | if err != nil { |
| 821 | return false, nil, fmt.Errorf("multi sub-index %d error: %v", i, err) |
| 822 | } |
| 823 | if !ok { |
| 824 | if c.AllowMissing { |
| 825 | break forloop |
| 826 | } else { |
| 827 | return false, nil, nil |
| 828 | } |
| 829 | } |
| 830 | |
| 831 | // Add each of the new values to each of the old values |
| 832 | builder = append(builder, vals) |
| 833 | |
| 834 | default: |
| 835 | return false, nil, fmt.Errorf("sub-index %d does not satisfy either SingleIndexer or MultiIndexer", i) |
| 836 | } |
| 837 | } |
| 838 | |
| 839 | // Start with something higher to avoid resizing if possible |
| 840 | out := make([][]byte, 0, len(c.Indexes)^3) |
| 841 | |
| 842 | // We are walking through the builder slice essentially in a depth-first fashion, |
| 843 | // building the prefix and leaves as we go. If AllowMissing is false, we only insert |
| 844 | // these full paths to leaves. Otherwise, we also insert each prefix along the way. |
| 845 | // This allows for lookup in FromArgs when AllowMissing is true that does not contain |
| 846 | // the full set of arguments. e.g. for {Foo, Bar} where an object has only the Foo |
| 847 | // field specified as "abc", it is valid to call FromArgs with just "abc". |
| 848 | var walkVals func([]byte, int) |
| 849 | walkVals = func(currPrefix []byte, depth int) { |
| 850 | if depth >= len(builder) { |
| 851 | return |
| 852 | } |