Skip to content

Commit 996af68

Browse files
implement expression updaters
1 parent 776aafc commit 996af68

File tree

4 files changed

+37
-26
lines changed

4 files changed

+37
-26
lines changed

src/FSharp.DynamoDB/Expression/ConditionalExpr.fs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -279,14 +279,14 @@ let extractQueryExpr (recordInfo : RecordInfo) (expr : Expr) : ConditionalExpres
279279
if not <| isValidFieldName key then
280280
invalidArg key "map key must be alphanumeric not starting with a digit"
281281

282-
Attribute_Exists (attr.Id.Append key)
282+
Attribute_Exists (attr.Id.AppendField key)
283283

284284
| SpecificCall2 <@ fun (x : Map<_,_>) y -> x.ContainsKey y @> (Some(AttributeGet attr), _, _, [key]) when key.IsClosed ->
285285
let key = evalRaw key
286286
if not <| isValidFieldName key then
287287
invalidArg key "map key must be alphanumeric not starting with a digit"
288288

289-
Attribute_Exists (attr.Id.Append key)
289+
Attribute_Exists (attr.Id.AppendField key)
290290

291291
| SpecificCall2 <@ BETWEEN @> (None, _, _, [value ; lower; upper]) ->
292292
let pickler = Pickler.resolveUntyped value.Type

src/FSharp.DynamoDB/Expression/ExprCommon.fs

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,24 @@ open Swensen.Unquote
2121
/// DynamoDB Attribute identifier
2222
type AttributeId =
2323
{
24-
Path : string
2524
RootName : string
2625
RootId : string
26+
NestedPath : string list
2727
Type : AttributeType
2828
}
2929
with
30+
member id.Id = String.concat "" (id.RootId :: id.NestedPath)
31+
member id.Name = String.concat "" (id.RootName :: id.NestedPath)
32+
member id.Tokens = id.RootName :: id.NestedPath
3033
member id.IsHashKey = id.Type = AttributeType.HashKey
3134
member id.IsRangeKey = id.Type = AttributeType.RangeKey
32-
member id.Append(suffix) = { id with Path = sprintf "%s.%s" id.Path suffix }
35+
member id.AppendField(suffix) = { id with NestedPath = id.NestedPath @ ["." + suffix] }
36+
member id.AppendIndex(index) = { id with NestedPath = id.NestedPath @ [sprintf "[%d]" index] }
3337

3438
static member FromKeySchema(schema : TableKeySchema) =
3539
let rootId = "#HKEY"
3640
let hkName = schema.HashKey.AttributeName
37-
{ Path = rootId ; RootId = rootId ; RootName = hkName ; Type = AttributeType.HashKey }
41+
{ RootId = rootId ; RootName = hkName ; NestedPath = [] ; Type = AttributeType.HashKey }
3842

3943
type RecordPropertyInfo with
4044
/// Gets an attribute Id for given record property that
@@ -67,17 +71,6 @@ with
6771

6872
aux ap
6973

70-
/// Gets a list of string tokens that identify the attribute path
71-
member ap.Tokens =
72-
let rec getTokens acc ap =
73-
match ap with
74-
| Root rp -> rp.Name :: acc
75-
| Nested (rp,p) -> getTokens ("." + rp.Name :: acc) p
76-
| Item(i,_,p) -> getTokens (sprintf ".[%d]" i :: acc) p
77-
| Optional(_,p) -> getTokens acc p
78-
79-
getTokens [] ap
80-
8174
/// Gets an attribute identifier for given Quoted attribute instace
8275
member ap.Id =
8376
let rec getTokens acc ap =
@@ -87,9 +80,9 @@ with
8780
| Optional(_,p) -> getTokens acc p
8881
| Root rp ->
8982
{
90-
Path = String.concat "" (rp.AttrId :: acc)
9183
RootId = rp.AttrId
9284
RootName = rp.Name
85+
NestedPath = acc
9386
Type = rp.AttributeType
9487
}
9588

@@ -192,7 +185,7 @@ type AttributeWriter(names : Dictionary<string, string>, values : Dictionary<str
192185

193186
member __.WriteAttibute(attr : AttributeId) =
194187
names.[attr.RootId] <- attr.RootName
195-
attr.Path
188+
attr.Id
196189

197190
/// Recognizes exprs of shape <@ fun p1 p2 ... -> body @>
198191
let extractExprParams (recordInfo : RecordInfo) (expr : Expr) =
@@ -220,9 +213,9 @@ let extractExprParams (recordInfo : RecordInfo) (expr : Expr) =
220213
// however 'r.Foo.Bar.[0]' and 'r.Foo.Bar.[1]' are not conflicting
221214
type private AttributeNode = { Value : string ; Children : ResizeArray<AttributeNode> }
222215
/// Detects conflicts in a collection of attribute paths
223-
let tryFindConflictingPaths (attrs : seq<QuotedAttribute>) =
216+
let tryFindConflictingPaths (attrs : seq<AttributeId>) =
224217
let root = new ResizeArray<AttributeNode>()
225-
let tryAppendPath (attr : QuotedAttribute) =
218+
let tryAppendPath (attr : AttributeId) =
226219
let tokens = attr.Tokens :> seq<string>
227220
let enum = tokens.GetEnumerator()
228221
let mutable ctx = root

src/FSharp.DynamoDB/Expression/ExpressionContainers.fs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,4 +94,22 @@ type UpdateExpression<'TRecord> internal (updateOps : UpdateOperations) =
9494
| :? UpdateExpression<'TRecord> as other -> updateOps.UpdateOps = other.UpdateOps.UpdateOps
9595
| _ -> false
9696

97-
override __.GetHashCode() = hash updateOps.UpdateOps
97+
override __.GetHashCode() = hash updateOps.UpdateOps
98+
99+
100+
type UpdateExpression =
101+
/// Combines a collection of compatible update expressions into a single expression.
102+
static member Combine([<ParamArray>]exprs : UpdateExpression<'TRecord> []) =
103+
match exprs with
104+
| [||] -> invalidArg "exprs" "must specify at least one update expression."
105+
| [|expr|] -> expr
106+
| _ ->
107+
108+
let uops = exprs |> Array.collect (fun e -> e.UpdateOps.UpdateOps)
109+
match uops |> Seq.map (fun o -> o.Attribute) |> tryFindConflictingPaths with
110+
| None -> ()
111+
| Some(p1,p2) ->
112+
let msg = sprintf "found conflicting paths '%s' and '%s' being accessed in update expression." p1 p2
113+
invalidArg "expr" msg
114+
115+
new UpdateExpression<'TRecord>({ UpdateOps = uops ; NParams = 0 })

src/FSharp.DynamoDB/Expression/UpdateExpr.fs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ let extractOpExprUpdaters (recordInfo : RecordInfo) (expr : Expr) : Intermediate
187187

188188
do extract body
189189

190-
match tryFindConflictingPaths attrs with
190+
match attrs |> Seq.map (fun attr -> attr.Id) |> tryFindConflictingPaths with
191191
| Some (p1,p2) ->
192192
let msg = sprintf "found conflicting paths '%s' and '%s' being accessed in update expression." p1 p2
193193
invalidArg "expr" msg
@@ -308,15 +308,15 @@ let extractUpdateOps (exprs : IntermediateUpdateExprs) =
308308

309309
| SpecificCall2 <@ Map.add @> (None, _, _, [keyE; value; AttributeGet attr]) when attr = parent ->
310310
let key = evalRaw keyE
311-
let attr = parent.Id.Append key
311+
let attr = parent.Id.AppendField key
312312
let ep = getElemPickler parent.Pickler
313313
match extractUpdateValue ep value with
314314
| Operand op when op = Undefined -> Remove attr
315315
| uv -> Set(attr, uv)
316316

317317
| SpecificCall2 <@ Map.remove @> (None, _, _, [keyE; AttributeGet attr]) when attr = parent ->
318318
let key = evalRaw keyE
319-
let attr = parent.Id.Append key
319+
let attr = parent.Id.AppendField key
320320
Remove attr
321321

322322
| e ->
@@ -333,7 +333,7 @@ let extractUpdateOps (exprs : IntermediateUpdateExprs) =
333333
if uop.Attribute.IsHashKey then invalidArg "expr" "update expression cannot update hash key."
334334
if uop.Attribute.IsRangeKey then invalidArg "expr" "update expression cannot update range key."
335335
uop)
336-
|> Seq.sortBy (fun uop -> uop.Id, uop.Attribute.Path)
336+
|> Seq.sortBy (fun uop -> uop.Id, uop.Attribute.Id)
337337
|> Seq.toArray
338338

339339
if updateOps.Length = 0 then invalidArg "expr" "No update clauses found in expression"
@@ -397,7 +397,7 @@ let applyParams (uops : UpdateOperations) (inputValues : obj[]) =
397397
uops.UpdateOps
398398
|> Seq.map applyUpdateOp
399399
|> Seq.filter (function Skip -> false | _ -> true)
400-
|> Seq.sortBy (fun uop -> uop.Id, uop.Attribute.Path)
400+
|> Seq.sortBy (fun uop -> uop.Id, uop.Attribute.Id)
401401
|> Seq.toArray
402402

403403
{ UpdateOps = updateOps' ; NParams = 0 }

0 commit comments

Comments
 (0)