Beispiel #1
0
// ReadOne loads a resource from Stretchr with the given path.
func (r *Request) ReadOne() (*Resource, error) {

	response, err := r.UnderlyingRequest.Read()

	if err != nil {
		return nil, err
	}

	responseObject := response.BodyObject()

	// return the error if there was one
	errs := GetErrorsFromResponseObject(responseObject)
	if len(errs) > 0 {
		return nil, errs[0]
	}

	switch responseObject.Data().(type) {
	case map[string]interface{}:
		resource := MakeResourceAt(r.UnderlyingRequest.Path())
		resource.data = objx.Map(responseObject.Data().(map[string]interface{})[common.ResponseObjectFieldData].([]interface{})[0].(map[string]interface{})).Copy()
		return resource, nil
	case []interface{}:
		return nil, ErrSingleObjectExpectedButGotArray
	case nil:
		return nil, ErrSingleObjectExpectedButGotNil
	}

	return nil, ErrSingleObjectExpectedButGotSomethingElse
}
Beispiel #2
0
// createMapResponse is a helper for generating a response value from
// a value of type map.
func createMapResponse(value reflect.Value, options objx.Map, constructor func(interface{}, interface{}) interface{}, domain string) interface{} {
	response := reflect.MakeMap(value.Type())
	for _, key := range value.MapKeys() {
		var elementOptions objx.Map
		keyStr := key.Interface().(string)
		if options != nil {
			var elementOptionsValue *objx.Value
			if options.Has(keyStr) {
				elementOptionsValue = options.Get(keyStr)
			} else if options.Has("*") {
				elementOptionsValue = options.Get("*")
			}
			if elementOptionsValue.IsMSI() {
				elementOptions = objx.Map(elementOptionsValue.MSI())
			} else if elementOptionsValue.IsObjxMap() {
				elementOptions = elementOptionsValue.ObjxMap()
			} else {
				panic("Don't know what to do with option")
			}
		}
		itemResponse := createResponseValue(value.MapIndex(key), elementOptions, constructor, domain)
		response.SetMapIndex(key, reflect.ValueOf(itemResponse))
	}
	return response.Interface()
}
Beispiel #3
0
func (t *Template) replaceTokens(record intf.Record) string {
	output := t.template
	mapper := objx.Map(record)

	for _, token := range t.tokens {
		value := t.castValueToString(mapper.Get(token))
		output = strings.Replace(output, `%{`+token+`}`, value, -1)
	}

	return output
}
Beispiel #4
0
// createStructResponse is a helper for generating a response value
// from a value of type struct.
func createStructResponse(value reflect.Value, options objx.Map, constructor func(interface{}, interface{}) interface{}, domain string) interface{} {
	structType := value.Type()

	// Support "database/sql".Null* types, and any other types
	// matching that structure
	if v, err := createNullableDbResponse(value, structType); err == nil {
		return v
	}

	response := make(objx.Map)

	for i := 0; i < value.NumField(); i++ {
		fieldType := structType.Field(i)
		fieldValue := value.Field(i)

		if fieldType.Anonymous {
			embeddedResponse := CreateResponse(fieldValue.Interface(), options, constructor, domain).(objx.Map)
			for key, value := range embeddedResponse {
				// Don't overwrite values from the base struct
				if _, ok := response[key]; !ok {
					response[key] = value
				}
			}
		} else if unicode.IsUpper(rune(fieldType.Name[0])) {
			name := ResponseTag(fieldType)
			switch name {
			case "-":
				continue
			default:
				var subOptions objx.Map
				if options != nil && (options.Has(name) || options.Has("*")) {
					var subOptionsValue *objx.Value
					if options.Has(name) {
						subOptionsValue = options.Get(name)
					} else {
						subOptionsValue = options.Get("*")
					}
					if subOptionsValue.IsMSI() {
						subOptions = objx.Map(subOptionsValue.MSI())
					} else if subOptionsValue.IsObjxMap() {
						subOptions = subOptionsValue.ObjxMap()
					} else {
						panic("Don't know what to do with option")
					}
				}
				response[name] = createResponseValue(fieldValue, subOptions, constructor, domain)
			}
		}
	}
	return response
}
// ConvertMSIToObjxMap recursively converts map[string]interface{}
// values to objx.Map.  This is designed around the return types of
// json.Unmarshal, so it may not work for non-json data.
func ConvertMSIToObjxMap(value interface{}) interface{} {
	switch src := value.(type) {
	case map[string]interface{}:
		for key, val := range src {
			src[key] = ConvertMSIToObjxMap(val)
		}
		return objx.Map(src)
	case []interface{}:
		for index, val := range src {
			src[index] = ConvertMSIToObjxMap(val)
		}
		return src
	}
	return value
}
Beispiel #6
0
// ReadMany loads many resources from Stretchr with the given path.
func (r *Request) ReadMany() (*ResourceCollection, error) {

	response, err := r.UnderlyingRequest.Read()

	if err != nil {
		return nil, err
	}

	responseObject := response.BodyObject()

	// return the error if there was one
	errs := GetErrorsFromResponseObject(responseObject)
	if len(errs) > 0 {
		return nil, errs[0]
	}

	if resourceArray, exists := responseObject.Data().(map[string]interface{})[common.ResponseObjectFieldData].([]interface{}); exists {
		resources := make([]*Resource, len(resourceArray))

		// populate the resources
		for resIndex, responseData := range resourceArray {
			resource := MakeResourceAt(r.UnderlyingRequest.Path())
			resource.data = objx.Map(responseData.(map[string]interface{})).Copy()
			resources[resIndex] = resource
		}

		resourceCollection := NewResourceCollection(resources)

		// set the total (if there is one)
		if total, ok := responseObject.Data().(map[string]interface{})[common.ResponseObjectFieldTotal]; ok {

			if totalNum, ok := total.(float64); ok {
				resourceCollection.Total = totalNum
			}
		}

		return resourceCollection, nil
	} else {
		return nil, ErrArrayObjectExpectedButGotSomethingElse
	}

}
Beispiel #7
0
func (engine *RuleEngine) DefineVirtualDevice(name string, obj objx.Map) error {
	title := name
	if obj.Has("title") {
		title = obj.Get("title").Str(name)
	}

	// if the device was for some reason defined in another script,
	// we must remove it
	engine.model.RemoveLocalDevice(name)

	dev := engine.model.EnsureLocalDevice(name, title)
	engine.cleanup.AddCleanup(func() {
		// runs when the rule file is reloaded
		engine.model.RemoveLocalDevice(name)
	})

	if !obj.Has("cells") {
		return nil
	}

	v := obj.Get("cells")
	var m objx.Map
	switch {
	case v.IsObjxMap():
		m = v.ObjxMap()
	case v.IsMSI():
		m = objx.Map(v.MSI())
	default:
		return fmt.Errorf("device %s doesn't have proper 'cells' property", name)
	}

	// Sorting cells by their names is not important when defining device
	// while the engine is not active because all the cells will be published
	// all at once when the engine starts.
	// On the other hand, when defining the device for the active engine
	// the newly added cells are published immediately and if their order
	// changes (map key order is random) the tests may break.
	cellNames := make([]string, 0, len(m))
	for cellName, _ := range m {
		cellNames = append(cellNames, cellName)
	}
	sort.Strings(cellNames)

	for _, cellName := range cellNames {
		maybeCellDef := m[cellName]
		cellDef, ok := maybeCellDef.(objx.Map)
		if !ok {
			cd, ok := maybeCellDef.(map[string]interface{})
			if !ok {
				return fmt.Errorf("%s/%s: bad cell definition", name, cellName)
			}
			cellDef = objx.Map(cd)
		}
		cellType, ok := cellDef["type"]
		if !ok {
			return fmt.Errorf("%s/%s: no cell type", name, cellName)
		}
		// FIXME: too much spaghetti for my taste
		if cellType == "pushbutton" {
			dev.SetButtonCell(cellName)
			continue
		}

		cellValue, ok := cellDef["value"]
		if !ok {
			return fmt.Errorf("%s/%s: cell value required for cell type %s",
				name, cellName, cellType)
		}

		cellReadonly := false
		cellReadonlyRaw, hasReadonly := cellDef["readonly"]

		if hasReadonly {
			cellReadonly, ok = cellReadonlyRaw.(bool)
			if !ok {
				return fmt.Errorf("%s/%s: non-boolean value of readonly property",
					name, cellName)
			}
		}

		if cellType == "range" {
			fmax := DEFAULT_CELL_MAX
			max, ok := cellDef["max"]
			if ok {
				fmax, ok = max.(float64)
				if !ok {
					return fmt.Errorf("%s/%s: non-numeric value of max property",
						name, cellName)
				}
			}
			// FIXME: can be float
			dev.SetRangeCell(cellName, cellValue, fmax, cellReadonly)
		} else {
			dev.SetCell(cellName, cellType.(string), cellValue, cellReadonly)
		}
	}

	return nil
}