You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

363 lines
9.0 KiB

  1. package dynamodb
  2. import (
  3. "encoding/json"
  4. "sort"
  5. )
  6. type msi map[string]interface{}
  7. type Query struct {
  8. buffer msi
  9. }
  10. func NewEmptyQuery() *Query {
  11. return &Query{msi{}}
  12. }
  13. func NewQuery(t *Table) *Query {
  14. q := &Query{msi{}}
  15. q.addTable(t)
  16. return q
  17. }
  18. // This way of specifing the key is used when doing a Get.
  19. // If rangeKey is "", it is assumed to not want to be used
  20. func (q *Query) AddKey(t *Table, key *Key) {
  21. k := t.Key
  22. keymap := msi{
  23. k.KeyAttribute.Name: msi{
  24. k.KeyAttribute.Type: key.HashKey},
  25. }
  26. if k.HasRange() {
  27. keymap[k.RangeAttribute.Name] = msi{k.RangeAttribute.Type: key.RangeKey}
  28. }
  29. q.buffer["Key"] = keymap
  30. }
  31. func keyAttributes(t *Table, key *Key) msi {
  32. k := t.Key
  33. out := msi{}
  34. out[k.KeyAttribute.Name] = msi{k.KeyAttribute.Type: key.HashKey}
  35. if k.HasRange() {
  36. out[k.RangeAttribute.Name] = msi{k.RangeAttribute.Type: key.RangeKey}
  37. }
  38. return out
  39. }
  40. func (q *Query) AddAttributesToGet(attributes []string) {
  41. if len(attributes) == 0 {
  42. return
  43. }
  44. q.buffer["AttributesToGet"] = attributes
  45. }
  46. func (q *Query) ConsistentRead(c bool) {
  47. if c == true {
  48. q.buffer["ConsistentRead"] = "true" //String "true", not bool true
  49. }
  50. }
  51. func (q *Query) AddGetRequestItems(tableKeys map[*Table][]Key) {
  52. requestitems := msi{}
  53. for table, keys := range tableKeys {
  54. keyslist := []msi{}
  55. for _, key := range keys {
  56. keyslist = append(keyslist, keyAttributes(table, &key))
  57. }
  58. requestitems[table.Name] = msi{"Keys": keyslist}
  59. }
  60. q.buffer["RequestItems"] = requestitems
  61. }
  62. func (q *Query) AddWriteRequestItems(tableItems map[*Table]map[string][][]Attribute) {
  63. b := q.buffer
  64. b["RequestItems"] = func() msi {
  65. out := msi{}
  66. for table, itemActions := range tableItems {
  67. out[table.Name] = func() interface{} {
  68. out2 := []interface{}{}
  69. // here breaks an order of array....
  70. // For now, we iterate over sorted key by action for stable testing
  71. keys := []string{}
  72. for k := range itemActions {
  73. keys = append(keys, k)
  74. }
  75. sort.Strings(keys)
  76. for ki := range keys {
  77. action := keys[ki]
  78. items := itemActions[action]
  79. for _, attributes := range items {
  80. Item_or_Key := map[bool]string{true: "Item", false: "Key"}[action == "Put"]
  81. out2 = append(out2, msi{action + "Request": msi{Item_or_Key: attributeList(attributes)}})
  82. }
  83. }
  84. return out2
  85. }()
  86. }
  87. return out
  88. }()
  89. }
  90. func (q *Query) AddCreateRequestTable(description TableDescriptionT) {
  91. b := q.buffer
  92. attDefs := []interface{}{}
  93. for _, attr := range description.AttributeDefinitions {
  94. attDefs = append(attDefs, msi{
  95. "AttributeName": attr.Name,
  96. "AttributeType": attr.Type,
  97. })
  98. }
  99. b["AttributeDefinitions"] = attDefs
  100. b["KeySchema"] = description.KeySchema
  101. b["TableName"] = description.TableName
  102. b["ProvisionedThroughput"] = msi{
  103. "ReadCapacityUnits": int(description.ProvisionedThroughput.ReadCapacityUnits),
  104. "WriteCapacityUnits": int(description.ProvisionedThroughput.WriteCapacityUnits),
  105. }
  106. if description.StreamSpecification.StreamEnabled {
  107. b["StreamSpecification"] = msi{
  108. "StreamEnabled": "true",
  109. "StreamViewType": description.StreamSpecification.StreamViewType,
  110. }
  111. }
  112. localSecondaryIndexes := []interface{}{}
  113. for _, ind := range description.LocalSecondaryIndexes {
  114. localSecondaryIndexes = append(localSecondaryIndexes, msi{
  115. "IndexName": ind.IndexName,
  116. "KeySchema": ind.KeySchema,
  117. "Projection": ind.Projection,
  118. })
  119. }
  120. globalSecondaryIndexes := []interface{}{}
  121. intmax := func(x, y int64) int64 {
  122. if x > y {
  123. return x
  124. }
  125. return y
  126. }
  127. for _, ind := range description.GlobalSecondaryIndexes {
  128. rec := msi{
  129. "IndexName": ind.IndexName,
  130. "KeySchema": ind.KeySchema,
  131. "Projection": ind.Projection,
  132. }
  133. // need at least one unit, and since go's max() is float based.
  134. rec["ProvisionedThroughput"] = msi{
  135. "ReadCapacityUnits": intmax(1, ind.ProvisionedThroughput.ReadCapacityUnits),
  136. "WriteCapacityUnits": intmax(1, ind.ProvisionedThroughput.WriteCapacityUnits),
  137. }
  138. globalSecondaryIndexes = append(globalSecondaryIndexes, rec)
  139. }
  140. if len(localSecondaryIndexes) > 0 {
  141. b["LocalSecondaryIndexes"] = localSecondaryIndexes
  142. }
  143. if len(globalSecondaryIndexes) > 0 {
  144. b["GlobalSecondaryIndexes"] = globalSecondaryIndexes
  145. }
  146. }
  147. func (q *Query) AddDeleteRequestTable(description TableDescriptionT) {
  148. b := q.buffer
  149. b["TableName"] = description.TableName
  150. }
  151. func (q *Query) AddUpdateRequestTable(description TableDescriptionT) {
  152. b := q.buffer
  153. attDefs := []interface{}{}
  154. for _, attr := range description.AttributeDefinitions {
  155. attDefs = append(attDefs, msi{
  156. "AttributeName": attr.Name,
  157. "AttributeType": attr.Type,
  158. })
  159. }
  160. if len(attDefs) > 0 {
  161. b["AttributeDefinitions"] = attDefs
  162. }
  163. b["TableName"] = description.TableName
  164. b["ProvisionedThroughput"] = msi{
  165. "ReadCapacityUnits": int(description.ProvisionedThroughput.ReadCapacityUnits),
  166. "WriteCapacityUnits": int(description.ProvisionedThroughput.WriteCapacityUnits),
  167. }
  168. }
  169. func (q *Query) AddKeyConditions(comparisons []AttributeComparison) {
  170. q.buffer["KeyConditions"] = buildComparisons(comparisons)
  171. }
  172. func (q *Query) AddLimit(limit int64) {
  173. q.buffer["Limit"] = limit
  174. }
  175. func (q *Query) AddSelect(value string) {
  176. q.buffer["Select"] = value
  177. }
  178. func (q *Query) AddIndex(value string) {
  179. q.buffer["IndexName"] = value
  180. }
  181. func (q *Query) ScanIndexDescending() {
  182. q.buffer["ScanIndexForward"] = "false"
  183. }
  184. /*
  185. "ScanFilter":{
  186. "AttributeName1":{"AttributeValueList":[{"S":"AttributeValue"}],"ComparisonOperator":"EQ"}
  187. },
  188. */
  189. func (q *Query) AddScanFilter(comparisons []AttributeComparison) {
  190. q.buffer["ScanFilter"] = buildComparisons(comparisons)
  191. }
  192. func (q *Query) AddParallelScanConfiguration(segment int, totalSegments int) {
  193. q.buffer["Segment"] = segment
  194. q.buffer["TotalSegments"] = totalSegments
  195. }
  196. func buildComparisons(comparisons []AttributeComparison) msi {
  197. out := msi{}
  198. for _, c := range comparisons {
  199. avlist := []interface{}{}
  200. for _, attributeValue := range c.AttributeValueList {
  201. avlist = append(avlist, msi{attributeValue.Type: attributeValue.Value})
  202. }
  203. out[c.AttributeName] = msi{
  204. "AttributeValueList": avlist,
  205. "ComparisonOperator": c.ComparisonOperator,
  206. }
  207. }
  208. return out
  209. }
  210. // The primary key must be included in attributes.
  211. func (q *Query) AddItem(attributes []Attribute) {
  212. q.buffer["Item"] = attributeList(attributes)
  213. }
  214. func (q *Query) AddUpdates(attributes []Attribute, action string) {
  215. updates := msi{}
  216. for _, a := range attributes {
  217. au := msi{
  218. "Value": msi{
  219. a.Type: map[bool]interface{}{true: a.SetValues, false: a.Value}[a.SetType()],
  220. },
  221. "Action": action,
  222. }
  223. // Delete 'Value' from AttributeUpdates if Type is not Set
  224. if action == "DELETE" && !a.SetType() {
  225. delete(au, "Value")
  226. }
  227. updates[a.Name] = au
  228. }
  229. q.buffer["AttributeUpdates"] = updates
  230. }
  231. func (q *Query) AddExpected(attributes []Attribute) {
  232. expected := msi{}
  233. for _, a := range attributes {
  234. value := msi{}
  235. if a.Exists != "" {
  236. value["Exists"] = a.Exists
  237. }
  238. // If set Exists to false, we must remove Value
  239. if value["Exists"] != "false" {
  240. value["Value"] = msi{a.Type: map[bool]interface{}{true: a.SetValues, false: a.Value}[a.SetType()]}
  241. }
  242. expected[a.Name] = value
  243. }
  244. q.buffer["Expected"] = expected
  245. }
  246. // Add the ReturnValues parameter, used in UpdateItem queries.
  247. func (q *Query) AddReturnValues(returnValues ReturnValues) {
  248. q.buffer["ReturnValues"] = string(returnValues)
  249. }
  250. // Add the UpdateExpression parameter, used in UpdateItem queries.
  251. func (q *Query) AddUpdateExpression(expression string) {
  252. q.buffer["UpdateExpression"] = expression
  253. }
  254. // Add the ConditionExpression parameter, used in UpdateItem queries.
  255. func (q *Query) AddConditionExpression(expression string) {
  256. q.buffer["ConditionExpression"] = expression
  257. }
  258. func (q *Query) AddExpressionAttributes(attributes []Attribute) {
  259. existing, ok := q.buffer["ExpressionAttributes"].(msi)
  260. if !ok {
  261. existing = msi{}
  262. q.buffer["ExpressionAttributes"] = existing
  263. }
  264. for key, val := range attributeList(attributes) {
  265. existing[key] = val
  266. }
  267. }
  268. func (q *Query) AddExclusiveStartStreamArn(arn string) {
  269. q.buffer["ExclusiveStartStreamArn"] = arn
  270. }
  271. func (q *Query) AddStreamArn(arn string) {
  272. q.buffer["StreamArn"] = arn
  273. }
  274. func (q *Query) AddExclusiveStartShardId(shardId string) {
  275. q.buffer["ExclusiveStartShardId"] = shardId
  276. }
  277. func (q *Query) AddShardId(shardId string) {
  278. q.buffer["ShardId"] = shardId
  279. }
  280. func (q *Query) AddShardIteratorType(shardIteratorType string) {
  281. q.buffer["ShardIteratorType"] = shardIteratorType
  282. }
  283. func (q *Query) AddSequenceNumber(sequenceNumber string) {
  284. q.buffer["SequenceNumber"] = sequenceNumber
  285. }
  286. func (q *Query) AddShardIterator(shardIterator string) {
  287. q.buffer["ShardIterator"] = shardIterator
  288. }
  289. func attributeList(attributes []Attribute) msi {
  290. b := msi{}
  291. for _, a := range attributes {
  292. //UGH!! (I miss the query operator)
  293. b[a.Name] = msi{a.Type: map[bool]interface{}{true: a.SetValues, false: a.Value}[a.SetType()]}
  294. }
  295. return b
  296. }
  297. func (q *Query) addTable(t *Table) {
  298. q.addTableByName(t.Name)
  299. }
  300. func (q *Query) addTableByName(tableName string) {
  301. q.buffer["TableName"] = tableName
  302. }
  303. func (q *Query) String() string {
  304. bytes, _ := json.Marshal(q.buffer)
  305. return string(bytes)
  306. }