github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/docs/apis/lang.IndexTemplateObject.md (about)

     1  # `lang.IndexTemplateObject()` (template API)
     2  
     3  > Returns element(s) from a data structure
     4  
     5  ## Description
     6  
     7  This is a template API you can use for your custom data types.
     8  
     9  It should only be called from `ReadIndex()` and `ReadNotIndex()` functions.
    10  
    11  This function ensures consistency with the index, `[`, builtin when used with
    12  different Murex data types. Thus making indexing a data type agnostic
    13  capability.
    14  
    15  
    16  
    17  ## Examples
    18  
    19  Example calling `lang.IndexTemplateObject()` function:
    20  
    21  ```go
    22  package json
    23  
    24  import (
    25  	"github.com/lmorg/murex/lang"
    26  	"github.com/lmorg/murex/utils/json"
    27  )
    28  
    29  func index(p *lang.Process, params []string) error {
    30  	var jInterface interface{}
    31  
    32  	b, err := p.Stdin.ReadAll()
    33  	if err != nil {
    34  		return err
    35  	}
    36  
    37  	err = json.Unmarshal(b, &jInterface)
    38  	if err != nil {
    39  		return err
    40  	}
    41  
    42  	marshaller := func(iface interface{}) ([]byte, error) {
    43  		return json.Marshal(iface, p.Stdout.IsTTY())
    44  	}
    45  
    46  	return lang.IndexTemplateObject(p, params, &jInterface, marshaller)
    47  }
    48  ```
    49  
    50  ## Detail
    51  
    52  ### API Source:
    53  
    54  ```go
    55  package lang
    56  
    57  import (
    58  	"errors"
    59  	"fmt"
    60  	"strconv"
    61  	"strings"
    62  
    63  	"github.com/lmorg/murex/lang/types"
    64  )
    65  
    66  // IndexTemplateObject is a handy standard indexer you can use in your custom data types for structured object types.
    67  // The point of this is to minimize code rewriting and standardising the behavior of the indexer.
    68  func IndexTemplateObject(p *Process, params []string, object *interface{}, marshaller func(interface{}) ([]byte, error)) error {
    69  	if p.IsNot {
    70  		return itoNot(p, params, object, marshaller)
    71  	}
    72  	return itoIndex(p, params, object, marshaller)
    73  }
    74  
    75  // itoIndex allow
    76  func itoIndex(p *Process, params []string, object *interface{}, marshaller func(interface{}) ([]byte, error)) error {
    77  	var objArray []interface{}
    78  	switch v := (*object).(type) {
    79  	case []interface{}:
    80  		for _, key := range params {
    81  			i, err := strconv.Atoi(key)
    82  			if err != nil {
    83  				return err
    84  			}
    85  			if i < 0 {
    86  				//i = len(v) + i
    87  				i += len(v)
    88  			}
    89  			if i >= len(v) {
    90  				return errors.New("key '" + key + "' greater than number of items in array")
    91  			}
    92  
    93  			if len(params) > 1 {
    94  				objArray = append(objArray, v[i])
    95  
    96  			} else {
    97  				switch v[i].(type) {
    98  				case nil:
    99  					p.Stdout.SetDataType(types.Null)
   100  				case bool:
   101  					p.Stdout.SetDataType(types.Boolean)
   102  					if v[i].(bool) {
   103  						p.Stdout.Write(types.TrueByte)
   104  					} else {
   105  						p.Stdout.Write(types.FalseByte)
   106  					}
   107  				case int:
   108  					p.Stdout.SetDataType(types.Integer)
   109  					s := strconv.Itoa(v[i].(int))
   110  					p.Stdout.Write([]byte(s))
   111  				case float64:
   112  					p.Stdout.SetDataType(types.Number)
   113  					s := types.FloatToString(v[i].(float64))
   114  					p.Stdout.Write([]byte(s))
   115  				case string:
   116  					p.Stdout.SetDataType(types.String)
   117  					p.Stdout.Write([]byte(v[i].(string)))
   118  				default:
   119  					b, err := marshaller(v[i])
   120  					if err != nil {
   121  						return err
   122  					}
   123  					p.Stdout.Writeln(b)
   124  				}
   125  			}
   126  		}
   127  		if len(objArray) > 0 {
   128  			b, err := marshaller(objArray)
   129  			if err != nil {
   130  				return err
   131  			}
   132  			p.Stdout.Writeln(b)
   133  		}
   134  		return nil
   135  
   136  	case map[string]interface{}:
   137  		var (
   138  			obj interface{}
   139  			err error
   140  		)
   141  
   142  		for i := range params {
   143  			if len(params[i]) > 2 && params[i][0] == '[' && params[i][len(params[i])-1] == ']' {
   144  				obj, err = ElementLookup(v, params[i][1:len(params[i])-1])
   145  				if err != nil {
   146  					return err
   147  				}
   148  
   149  			} else {
   150  
   151  				switch {
   152  				case v[params[i]] != nil:
   153  					obj = v[params[i]]
   154  				case v[strings.Title(params[i])] != nil:
   155  					obj = v[strings.Title(params[i])]
   156  				case v[strings.ToLower(params[i])] != nil:
   157  					obj = v[strings.ToLower(params[i])]
   158  				case v[strings.ToUpper(params[i])] != nil:
   159  					obj = v[strings.ToUpper(params[i])]
   160  				default:
   161  					return errors.New("key '" + params[i] + "' not found")
   162  				}
   163  			}
   164  
   165  			if len(params) > 1 {
   166  				objArray = append(objArray, obj)
   167  
   168  			} else {
   169  				switch obj := obj.(type) {
   170  				case nil:
   171  					p.Stdout.SetDataType(types.Null)
   172  				case bool:
   173  					p.Stdout.SetDataType(types.Boolean)
   174  					if obj {
   175  						p.Stdout.Write(types.TrueByte)
   176  					} else {
   177  						p.Stdout.Write(types.FalseByte)
   178  					}
   179  				case int:
   180  					p.Stdout.SetDataType(types.Integer)
   181  					s := strconv.Itoa(obj)
   182  					p.Stdout.Write([]byte(s))
   183  				case float64:
   184  					p.Stdout.SetDataType(types.Number)
   185  					s := types.FloatToString(obj)
   186  					p.Stdout.Write([]byte(s))
   187  				case string:
   188  					p.Stdout.SetDataType(types.String)
   189  					p.Stdout.Write([]byte(obj))
   190  				default:
   191  					b, err := marshaller(obj)
   192  					if err != nil {
   193  						return err
   194  					}
   195  					p.Stdout.Writeln(b)
   196  				}
   197  			}
   198  		}
   199  		if len(objArray) > 0 {
   200  			b, err := marshaller(objArray)
   201  			if err != nil {
   202  				return err
   203  			}
   204  			p.Stdout.Writeln(b)
   205  		}
   206  		return nil
   207  
   208  	case map[interface{}]interface{}:
   209  		for i := range params {
   210  			//if v[key] == nil {
   211  			//	return errors.New("key '" + key + "' not found.")
   212  			//}
   213  			switch {
   214  			case v[params[i]] != nil:
   215  			case v[strings.Title(params[i])] != nil:
   216  				params[i] = strings.Title(params[i])
   217  			case v[strings.ToLower(params[i])] != nil:
   218  				params[i] = strings.ToLower(params[i])
   219  			case v[strings.ToUpper(params[i])] != nil:
   220  				params[i] = strings.ToUpper(params[i])
   221  			//case v[strings.ToTitle(params[i])] != nil:
   222  			//	params[i] = strings.ToTitle(params[i])
   223  			default:
   224  				return errors.New("key '" + params[i] + "' not found")
   225  			}
   226  
   227  			if len(params) > 1 {
   228  				objArray = append(objArray, v[params[i]])
   229  
   230  			} else {
   231  				switch v[params[i]].(type) {
   232  				case nil:
   233  					p.Stdout.SetDataType(types.Null)
   234  				case bool:
   235  					p.Stdout.SetDataType(types.Boolean)
   236  					if v[params[i]].(bool) {
   237  						p.Stdout.Write(types.TrueByte)
   238  					} else {
   239  						p.Stdout.Write(types.FalseByte)
   240  					}
   241  				case int:
   242  					p.Stdout.SetDataType(types.Integer)
   243  					s := strconv.Itoa(v[params[i]].(int))
   244  					p.Stdout.Write([]byte(s))
   245  				case float64:
   246  					p.Stdout.SetDataType(types.Number)
   247  					s := types.FloatToString(v[params[i]].(float64))
   248  					p.Stdout.Write([]byte(s))
   249  				case string:
   250  					p.Stdout.SetDataType(types.String)
   251  					p.Stdout.Write([]byte(v[params[i]].(string)))
   252  				default:
   253  					b, err := marshaller(v[params[i]])
   254  					if err != nil {
   255  						return err
   256  					}
   257  					p.Stdout.Writeln(b)
   258  				}
   259  			}
   260  		}
   261  		if len(objArray) > 0 {
   262  			b, err := marshaller(objArray)
   263  			if err != nil {
   264  				return err
   265  			}
   266  			p.Stdout.Writeln(b)
   267  		}
   268  		return nil
   269  
   270  	default:
   271  		return errors.New("object cannot be indexed")
   272  	}
   273  }
   274  
   275  // itoNot requires the indexes to be explicit
   276  func itoNot(p *Process, params []string, object *interface{}, marshaller func(interface{}) ([]byte, error)) error {
   277  	switch v := (*object).(type) {
   278  	case []interface{}:
   279  		var objArray []interface{}
   280  		not := make(map[int]bool)
   281  		for _, key := range params {
   282  			i, err := strconv.Atoi(key)
   283  			if err != nil {
   284  				return err
   285  			}
   286  			if i < 0 {
   287  				return errors.New("cannot have negative keys in array")
   288  			}
   289  			if i >= len(v) {
   290  				return errors.New("Key '" + key + "' greater than number of items in array")
   291  			}
   292  
   293  			not[i] = true
   294  		}
   295  
   296  		for i := range v {
   297  			if !not[i] {
   298  				objArray = append(objArray, v[i])
   299  			}
   300  		}
   301  
   302  		//if len(objArray) > 0 {
   303  		b, err := marshaller(objArray)
   304  		if err != nil {
   305  			return err
   306  		}
   307  		_, err = p.Stdout.Writeln(b)
   308  		//}
   309  		return err
   310  
   311  	case map[string]interface{}:
   312  		objMap := make(map[string]interface{})
   313  		not := make(map[string]bool)
   314  		for _, key := range params {
   315  			not[key] = true
   316  			not[strings.Title(key)] = true
   317  			not[strings.ToLower(key)] = true
   318  			not[strings.ToUpper(key)] = true
   319  			//not[strings.ToTitle(key)] = true
   320  		}
   321  
   322  		for s := range v {
   323  			if !not[s] {
   324  				objMap[s] = v[s]
   325  			}
   326  		}
   327  
   328  		//if len(objMap) > 0 {
   329  		b, err := marshaller(objMap)
   330  		if err != nil {
   331  			return err
   332  		}
   333  		p.Stdout.Writeln(b)
   334  		//}
   335  		return nil
   336  
   337  	case map[interface{}]interface{}:
   338  		objMap := make(map[interface{}]interface{})
   339  		not := make(map[string]bool)
   340  		for _, key := range params {
   341  			not[key] = true
   342  			not[strings.Title(key)] = true
   343  			not[strings.ToLower(key)] = true
   344  			not[strings.ToUpper(key)] = true
   345  			//not[strings.ToTitle(key)] = true
   346  		}
   347  
   348  		for iface := range v {
   349  			s := fmt.Sprint(iface)
   350  			if !not[s] {
   351  				objMap[iface] = v[iface]
   352  			}
   353  		}
   354  
   355  		//if len(objMap) > 0 {
   356  		b, err := marshaller(objMap)
   357  		if err != nil {
   358  			return err
   359  		}
   360  		_, err = p.Stdout.Writeln(b)
   361  		//}
   362  		return err
   363  
   364  	default:
   365  		return errors.New("object cannot be !indexed")
   366  	}
   367  }
   368  ```
   369  
   370  ## Parameters
   371  
   372  1. `*lang.Process`: Process's runtime state. Typically expressed as the variable `p` 
   373  2. `[]string`: slice of parameters used in `[` / `![` 
   374  3. `*interface{}`: a pointer to the data structure being indexed
   375  4. `func(interface{}) ([]byte, error)`: data type marshaller function
   376  
   377  ## See Also
   378  
   379  * [apis/`ReadArray()` (type)](../apis/ReadArray.md):
   380    Read from a data type one array element at a time
   381  * [apis/`ReadArrayWithType()` (type)](../apis/ReadArrayWithType.md):
   382    Read from a data type one array element at a time and return the elements contents and data type
   383  * [apis/`ReadIndex()` (type)](../apis/ReadIndex.md):
   384    Data type handler for the index, `[`, builtin
   385  * [apis/`ReadMap()` (type)](../apis/ReadMap.md):
   386    Treat data type as a key/value structure and read its contents
   387  * [apis/`ReadNotIndex()` (type)](../apis/ReadNotIndex.md):
   388    Data type handler for the bang-prefixed index, `![`, builtin
   389  * [apis/`WriteArray()` (type)](../apis/WriteArray.md):
   390    Write a data type, one array element at a time
   391  * [apis/`lang.IndexTemplateTable()` (template API)](../apis/lang.IndexTemplateTable.md):
   392    Returns element(s) from a table
   393  * [parser/index](../parser/item-index.md):
   394    Outputs an element from an array, map or table
   395  
   396  <hr/>
   397  
   398  This document was generated from [lang/stdio/interface_doc.yaml](https://github.com/lmorg/murex/blob/master/lang/stdio/interface_doc.yaml).