Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[runtime] Support set map value by key #2

Closed
pingginp opened this issue Sep 15, 2018 · 3 comments
Closed

[runtime] Support set map value by key #2

pingginp opened this issue Sep 15, 2018 · 3 comments
Labels
comp/runtime cqlc runtime, the query builder
Milestone

Comments

@pingginp
Copy link
Owner

pingginp commented Sep 15, 2018

Follow on relops#39

AppendSlice is the base point to follow

const (
	NoCollectionType CollectionType = iota
	ListType
	SetType
	MapType
)

func appendList(c *Context, col ListColumn, values interface{}) {
	b := ColumnBinding{Column: col, Value: values, Incremental: true, CollectionType: ListType, CollectionOperationType: Append}
	c.Bindings = append(c.Bindings, b)
}

func prependList(c *Context, col ListColumn, values interface{}) {
	b := ColumnBinding{Column: col, Value: values, Incremental: true, CollectionType: ListType, CollectionOperationType: Prepend}
	c.Bindings = append(c.Bindings, b)
}

func removeList(c *Context, col ListColumn, values interface{}) {
	b := ColumnBinding{Column: col, Value: values, Incremental: true, CollectionType: ListType, CollectionOperationType: RemoveByValue}
	c.Bindings = append(c.Bindings, b)
}

func renderUpdate(ctx *Context, buf *bytes.Buffer, counterTable bool) {
           // ....
              switch binding.CollectionType {
			case ListType:
				switch binding.CollectionOperationType {
				case Append:
					setFragments[i] = fmt.Sprintf("%s = %s + ?", col, col)
				case Prepend:
					setFragments[i] = fmt.Sprintf("%s = ? + %s", col, col)
				case RemoveByValue:
					setFragments[i] = fmt.Sprintf("%s = %s - ?", col, col)
				}
			default:
				setFragments[i] = fmt.Sprintf("%s = ?", col)
			}
}
@pingginp pingginp mentioned this issue Sep 15, 2018
4 tasks
@pingginp
Copy link
Owner Author

the main challenge is map requires a column name and two value, so we will have two ? in query instead of just one ...

Although AppendStringSlice has values, it used for binding as value, not in query, only col is used in query

func (c *Context) AppendStringSlice(col StringSliceColumn, values ...string) SetValueStep {
	appendList(c, col, values)
	return c
}
SetStringStringMapValue(col StringStringMapColumn, key string, value string) SetValueStep
setFragments[i] = fmt.Sprintf("%s [?] = ?", col)

@pingginp
Copy link
Owner Author

pingginp commented Sep 15, 2018

it seems multiple ? is already handled in binding due to WHERE fo IN (?,?,?)

func (c *Context) Prepare(s *gocql.Session) (*gocql.Query, error) {
	// The reason why this is so dynamic is because of WHERE foo IN (?,?,?) clauses
	// The factoring for an IN clause is bad, since we are storing an array into the value
	// and using reflection to dig it out again
	// This should be more strongly typed
placeHolders := make([]interface{}, 0)

	for _, cond := range c.Conditions {
		v := cond.Binding.Value

		switch reflect.TypeOf(v).Kind() {
		case reflect.Slice:
			{
				s := reflect.ValueOf(v)
				for i := 0; i < s.Len(); i++ {
					placeHolders = append(placeHolders, s.Index(i).Interface())
				}
			}
		case reflect.Array:
			{

				// Not really happy about having to special case UUIDs
				// but this works for now

				if val, ok := v.(gocql.UUID); ok {
					placeHolders = append(placeHolders, val.Bytes())
				} else {
					return nil, bindingErrorf("Cannot bind component: %+v (type: %s)", v, reflect.TypeOf(v))
				}
			}
		default:
			{
				placeHolders = append(placeHolders, &v)
			}
		}
	}
}

pingginp added a commit that referenced this issue Sep 15, 2018
- only support `col[?] = ?`, value binding should work, because there
was `WHERE foo in (?,?,?)` so in `Prepare` cqlc would flat the slice
before passing to gocql
- #2
- [ ] TODO: need to test against a real database to see if it works
pingginp added a commit that referenced this issue Sep 15, 2018
- when insert, use SetStringStringMap
- when update, SetStringStringMapValue didn't work ... got gocql: expected 3 values send got 2
pingginp added a commit that referenced this issue Sep 15, 2018
- BuildStatement is called by Exec, Prepare is called by Fetch,
previously flatten is only applied in Prepare
@pingginp
Copy link
Owner Author

pingginp commented Sep 15, 2018

summarize what need to be done in order to get this work (previous commit already works, need to tweak the test and clean up code)

Actually it's all just runtime ....

  • in tmpl/columns.tmpl
    • in SetStepValue interface, add Set{{Type1}}{{Type2}}MapValue(col, key {{type1}}, value {{type2}}
    • in Context methods, add the impl method with same name and call setMap
  • run make cqlc/columns.go to generate using column_generator.go
  • add setMap and use []interface{}{key, value} as Value for binding, set type to MapType and op to SetByKey
  • in renderUpdate, use %s[?] = ? where %s is from col

BuildStatement, flatten binding, (copy from Prepare), former is used by Exec (update & insert) and latter is used by Fetch (select)

  • NOTE: we added new struct KeyValue to avoid flatten slice value that should be kept as slice
  • in old code, they were using &v for placeholder, it's pointer to interface, I don't know why it didn't trigger error, because gocql traverse ptr until it's a value?

@pingginp pingginp changed the title [gen] Support set map value by key [gen][run] Support set map value by key Sep 15, 2018
@pingginp pingginp changed the title [gen][run] Support set map value by key [run] Support set map value by key Sep 15, 2018
@pingginp pingginp added this to the 0.11.0 milestone Sep 15, 2018
@pingginp pingginp changed the title [run] Support set map value by key [runtime] Support set map value by key Sep 15, 2018
@pingginp pingginp added the comp/runtime cqlc runtime, the query builder label Sep 15, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
comp/runtime cqlc runtime, the query builder
Projects
None yet
Development

No branches or pull requests

1 participant