Skip to content

Commit 3d847c2

Browse files
implement GetHashKeyCondition implementation
1 parent 59050d0 commit 3d847c2

File tree

3 files changed

+66
-37
lines changed

3 files changed

+66
-37
lines changed

src/FSharp.DynamoDB/Expression/ConditionalExpr.fs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,15 @@ let mkItemNotExistsCondition (schema : TableKeySchema) =
419419
NParams = 0
420420
}
421421

422+
/// Generates a hash key equality condition for given key schema
423+
let mkHashKeyEqualityCondition (schema : TableKeySchema) (av : AttributeValue) =
424+
let hkAttrId = AttributeId.FromKeySchema schema
425+
{
426+
QueryExpr = Compare(EQ, Attribute hkAttrId, Value (wrap av))
427+
IsKeyConditionCompatible = true
428+
NParams = 0
429+
}
430+
422431
type ConditionalExpression with
423432
member cond.Apply([<ParamArray>]parameters : obj[]) =
424433
applyParams cond parameters

src/FSharp.DynamoDB/RecordTemplate.fs

Lines changed: 48 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ open FSharp.DynamoDB.UpdateExpr
1515

1616
/// DynamoDB table template defined by provided F# record type
1717
[<Sealed; AutoSerializable(false)>]
18-
type RecordTemplate<'Record> internal () =
19-
let pickler = Pickler.resolve<'Record>() :?> RecordPickler<'Record>
18+
type RecordTemplate<'TRecord> internal () =
19+
let pickler = Pickler.resolve<'TRecord>() :?> RecordPickler<'TRecord>
2020
let keyStructure = KeyStructure.FromRecordInfo pickler.RecordInfo
2121
let keySchema = TableKeySchema.OfKeyStructure keyStructure
2222

@@ -30,153 +30,153 @@ type RecordTemplate<'Record> internal () =
3030
/// Extracts the key that corresponds to supplied record instance.
3131
/// </summary>
3232
/// <param name="item">Input record instance.</param>
33-
member __.ExtractKey(record : 'Record) =
33+
member __.ExtractKey(record : 'TRecord) =
3434
KeyStructure.ExtractKey(keyStructure, pickler.RecordInfo, record)
3535

3636
/// Generates a conditional which verifies whether an item already exists.
3737
member __.ItemExists =
3838
let cond = mkItemExistsCondition keySchema
39-
new ConditionExpression<'Record>(cond)
39+
new ConditionExpression<'TRecord>(cond)
4040

4141
/// Generates a conditional which verifies whether an item does not already exist.
4242
member __.ItemDoesNotExist =
4343
let cond = mkItemNotExistsCondition keySchema
44-
new ConditionExpression<'Record>(cond)
44+
new ConditionExpression<'TRecord>(cond)
4545

4646
/// <summary>
4747
/// Precomputes a DynamoDB conditional expression using
4848
/// supplied quoted record predicate.
4949
/// </summary>
5050
/// <param name="expr">Quoted record predicate.</param>
51-
member __.PrecomputeConditionalExpr(expr : Expr<'Record -> bool>) : ConditionExpression<'Record> =
51+
member __.PrecomputeConditionalExpr(expr : Expr<'TRecord -> bool>) : ConditionExpression<'TRecord> =
5252
let cexpr = ConditionalExpression.Extract pickler.RecordInfo expr
53-
new ConditionExpression<'Record>(cexpr)
53+
new ConditionExpression<'TRecord>(cexpr)
5454

5555
/// <summary>
5656
/// Precomputes a DynamoDB conditional expression using
5757
/// supplied quoted record predicate.
5858
/// </summary>
5959
/// <param name="expr">Quoted record predicate.</param>
60-
member __.PrecomputeConditionalExpr(expr : Expr<'I1 -> 'Record -> bool>) : 'I1 -> ConditionExpression<'Record> =
60+
member __.PrecomputeConditionalExpr(expr : Expr<'I1 -> 'TRecord -> bool>) : 'I1 -> ConditionExpression<'TRecord> =
6161
let f = ConditionalExpression.Extract pickler.RecordInfo expr
62-
fun i1 -> new ConditionExpression<'Record>(f.Apply(i1))
62+
fun i1 -> new ConditionExpression<'TRecord>(f.Apply(i1))
6363

6464
/// <summary>
6565
/// Precomputes a DynamoDB conditional expression using
6666
/// supplied quoted record predicate.
6767
/// </summary>
6868
/// <param name="expr">Quoted record predicate.</param>
69-
member __.PrecomputeConditionalExpr(expr : Expr<'I1 -> 'I2 -> 'Record -> bool>) : 'I1 -> 'I2 -> ConditionExpression<'Record> =
69+
member __.PrecomputeConditionalExpr(expr : Expr<'I1 -> 'I2 -> 'TRecord -> bool>) : 'I1 -> 'I2 -> ConditionExpression<'TRecord> =
7070
let f = ConditionalExpression.Extract pickler.RecordInfo expr
71-
fun i1 i2 -> new ConditionExpression<'Record>(f.Apply(i1, i2))
71+
fun i1 i2 -> new ConditionExpression<'TRecord>(f.Apply(i1, i2))
7272

7373
/// <summary>
7474
/// Precomputes a DynamoDB conditional expression using
7575
/// supplied quoted record predicate.
7676
/// </summary>
7777
/// <param name="expr">Quoted record predicate.</param>
78-
member __.PrecomputeConditionalExpr(expr : Expr<'I1 -> 'I2 -> 'I3 -> 'Record -> bool>) : 'I1 -> 'I2 -> 'I3 -> ConditionExpression<'Record> =
78+
member __.PrecomputeConditionalExpr(expr : Expr<'I1 -> 'I2 -> 'I3 -> 'TRecord -> bool>) : 'I1 -> 'I2 -> 'I3 -> ConditionExpression<'TRecord> =
7979
let f = ConditionalExpression.Extract pickler.RecordInfo expr
80-
fun i1 i2 i3 -> new ConditionExpression<'Record>(f.Apply(i1, i2, i3))
80+
fun i1 i2 i3 -> new ConditionExpression<'TRecord>(f.Apply(i1, i2, i3))
8181

8282
/// <summary>
8383
/// Precomputes a DynamoDB conditional expression using
8484
/// supplied quoted record predicate.
8585
/// </summary>
8686
/// <param name="expr">Quoted record predicate.</param>
87-
member __.PrecomputeConditionalExpr(expr : Expr<'I1 -> 'I2 -> 'I3 -> 'I4 -> 'Record -> bool>) : 'I1 -> 'I2 -> 'I3 -> 'I4 -> ConditionExpression<'Record> =
87+
member __.PrecomputeConditionalExpr(expr : Expr<'I1 -> 'I2 -> 'I3 -> 'I4 -> 'TRecord -> bool>) : 'I1 -> 'I2 -> 'I3 -> 'I4 -> ConditionExpression<'TRecord> =
8888
let f = ConditionalExpression.Extract pickler.RecordInfo expr
89-
fun i1 i2 i3 i4 -> new ConditionExpression<'Record>(f.Apply(i1, i2, i3, i4))
89+
fun i1 i2 i3 i4 -> new ConditionExpression<'TRecord>(f.Apply(i1, i2, i3, i4))
9090

9191
/// <summary>
9292
/// Precomputes a DynamoDB update expression using
9393
/// supplied quoted record update expression.
9494
/// </summary>
9595
/// <param name="expr">Quoted record update expression.</param>
96-
member __.PrecomputeUpdateExpr(expr : Expr<'Record -> 'Record>) : UpdateExpression<'Record> =
96+
member __.PrecomputeUpdateExpr(expr : Expr<'TRecord -> 'TRecord>) : UpdateExpression<'TRecord> =
9797
let uops = UpdateOperations.ExtractUpdateExpr pickler.RecordInfo expr
98-
new UpdateExpression<'Record>(uops)
98+
new UpdateExpression<'TRecord>(uops)
9999

100100
/// <summary>
101101
/// Precomputes a DynamoDB update expression using
102102
/// supplied quoted record update expression.
103103
/// </summary>
104104
/// <param name="expr">Quoted record update expression.</param>
105-
member __.PrecomputeUpdateExpr(expr : Expr<'I1 -> 'Record -> 'Record>) : 'I1 -> UpdateExpression<'Record> =
105+
member __.PrecomputeUpdateExpr(expr : Expr<'I1 -> 'TRecord -> 'TRecord>) : 'I1 -> UpdateExpression<'TRecord> =
106106
let uops = UpdateOperations.ExtractUpdateExpr pickler.RecordInfo expr
107-
fun i1 -> new UpdateExpression<'Record>(uops.Apply(i1))
107+
fun i1 -> new UpdateExpression<'TRecord>(uops.Apply(i1))
108108

109109
/// <summary>
110110
/// Precomputes a DynamoDB update expression using
111111
/// supplied quoted record update expression.
112112
/// </summary>
113113
/// <param name="expr">Quoted record update expression.</param>
114-
member __.PrecomputeUpdateExpr(expr : Expr<'I1 -> 'I2 -> 'Record -> 'Record>) : 'I1 -> 'I2 -> UpdateExpression<'Record> =
114+
member __.PrecomputeUpdateExpr(expr : Expr<'I1 -> 'I2 -> 'TRecord -> 'TRecord>) : 'I1 -> 'I2 -> UpdateExpression<'TRecord> =
115115
let uops = UpdateOperations.ExtractUpdateExpr pickler.RecordInfo expr
116-
fun i1 i2 -> new UpdateExpression<'Record>(uops.Apply(i1, i2))
116+
fun i1 i2 -> new UpdateExpression<'TRecord>(uops.Apply(i1, i2))
117117

118118
/// <summary>
119119
/// Precomputes a DynamoDB update expression using
120120
/// supplied quoted record update expression.
121121
/// </summary>
122122
/// <param name="expr">Quoted record update expression.</param>
123-
member __.PrecomputeUpdateExpr(expr : Expr<'I1 -> 'I2 -> 'I3 -> 'Record -> 'Record>) : 'I1 -> 'I2 -> 'I3 -> UpdateExpression<'Record> =
123+
member __.PrecomputeUpdateExpr(expr : Expr<'I1 -> 'I2 -> 'I3 -> 'TRecord -> 'TRecord>) : 'I1 -> 'I2 -> 'I3 -> UpdateExpression<'TRecord> =
124124
let uops = UpdateOperations.ExtractUpdateExpr pickler.RecordInfo expr
125-
fun i1 i2 i3 -> new UpdateExpression<'Record>(uops.Apply(i1, i2, i3))
125+
fun i1 i2 i3 -> new UpdateExpression<'TRecord>(uops.Apply(i1, i2, i3))
126126

127127
/// <summary>
128128
/// Precomputes a DynamoDB update expression using
129129
/// supplied quoted record update expression.
130130
/// </summary>
131131
/// <param name="expr">Quoted record update expression.</param>
132-
member __.PrecomputeUpdateExpr(expr : Expr<'I1 -> 'I2 -> 'I3 -> 'I4 -> 'Record -> 'Record>) : 'I1 -> 'I2 -> 'I3 -> 'I4 -> UpdateExpression<'Record> =
132+
member __.PrecomputeUpdateExpr(expr : Expr<'I1 -> 'I2 -> 'I3 -> 'I4 -> 'TRecord -> 'TRecord>) : 'I1 -> 'I2 -> 'I3 -> 'I4 -> UpdateExpression<'TRecord> =
133133
let uops = UpdateOperations.ExtractUpdateExpr pickler.RecordInfo expr
134-
fun i1 i2 i3 i4 -> new UpdateExpression<'Record>(uops.Apply(i1, i2, i3, i4))
134+
fun i1 i2 i3 i4 -> new UpdateExpression<'TRecord>(uops.Apply(i1, i2, i3, i4))
135135

136136
/// <summary>
137137
/// Precomputes a DynamoDB update expression using
138138
/// supplied quoted record update operations.
139139
/// </summary>
140140
/// <param name="expr">Quoted record update operations.</param>
141-
member __.PrecomputeUpdateExpr(expr : Expr<'TRecord -> UpdateOp>) : UpdateExpression<'Record> =
141+
member __.PrecomputeUpdateExpr(expr : Expr<'TRecord -> UpdateOp>) : UpdateExpression<'TRecord> =
142142
let uops = UpdateOperations.ExtractOpExpr pickler.RecordInfo expr
143-
new UpdateExpression<'Record>(uops)
143+
new UpdateExpression<'TRecord>(uops)
144144

145145
/// <summary>
146146
/// Precomputes a DynamoDB update expression using
147147
/// supplied quoted record update operations.
148148
/// </summary>
149149
/// <param name="expr">Quoted record update operations.</param>
150-
member __.PrecomputeUpdateExpr(expr : Expr<'I1 -> 'TRecord -> UpdateOp>) : 'I1 -> UpdateExpression<'Record> =
150+
member __.PrecomputeUpdateExpr(expr : Expr<'I1 -> 'TRecord -> UpdateOp>) : 'I1 -> UpdateExpression<'TRecord> =
151151
let uops = UpdateOperations.ExtractOpExpr pickler.RecordInfo expr
152-
fun i1 -> new UpdateExpression<'Record>(uops.Apply i1)
152+
fun i1 -> new UpdateExpression<'TRecord>(uops.Apply i1)
153153

154154
/// <summary>
155155
/// Precomputes a DynamoDB update expression using
156156
/// supplied quoted record update operations.
157157
/// </summary>
158158
/// <param name="expr">Quoted record update operations.</param>
159-
member __.PrecomputeUpdateExpr(expr : Expr<'I1 -> 'I2 -> 'TRecord -> UpdateOp>) : 'I1 -> 'I2 -> UpdateExpression<'Record> =
159+
member __.PrecomputeUpdateExpr(expr : Expr<'I1 -> 'I2 -> 'TRecord -> UpdateOp>) : 'I1 -> 'I2 -> UpdateExpression<'TRecord> =
160160
let uops = UpdateOperations.ExtractOpExpr pickler.RecordInfo expr
161-
fun i1 i2 -> new UpdateExpression<'Record>(uops.Apply(i1, i2))
161+
fun i1 i2 -> new UpdateExpression<'TRecord>(uops.Apply(i1, i2))
162162

163163
/// <summary>
164164
/// Precomputes a DynamoDB update expression using
165165
/// supplied quoted record update operations.
166166
/// </summary>
167167
/// <param name="expr">Quoted record update operations.</param>
168-
member __.PrecomputeUpdateExpr(expr : Expr<'I1 -> 'I2 -> 'I3 -> 'TRecord -> UpdateOp>) : 'I1 -> 'I2 -> 'I3 -> UpdateExpression<'Record> =
168+
member __.PrecomputeUpdateExpr(expr : Expr<'I1 -> 'I2 -> 'I3 -> 'TRecord -> UpdateOp>) : 'I1 -> 'I2 -> 'I3 -> UpdateExpression<'TRecord> =
169169
let uops = UpdateOperations.ExtractOpExpr pickler.RecordInfo expr
170-
fun i1 i2 i3 -> new UpdateExpression<'Record>(uops.Apply(i1, i2, i3))
170+
fun i1 i2 i3 -> new UpdateExpression<'TRecord>(uops.Apply(i1, i2, i3))
171171

172172
/// <summary>
173173
/// Precomputes a DynamoDB update expression using
174174
/// supplied quoted record update operations.
175175
/// </summary>
176176
/// <param name="expr">Quoted record update operations.</param>
177-
member __.PrecomputeUpdateExpr(expr : Expr<'I1 -> 'I2 -> 'I3 -> 'I4 -> 'TRecord -> UpdateOp>) : 'I1 -> 'I2 -> 'I3 -> 'I4 -> UpdateExpression<'Record> =
177+
member __.PrecomputeUpdateExpr(expr : Expr<'I1 -> 'I2 -> 'I3 -> 'I4 -> 'TRecord -> UpdateOp>) : 'I1 -> 'I2 -> 'I3 -> 'I4 -> UpdateExpression<'TRecord> =
178178
let uops = UpdateOperations.ExtractOpExpr pickler.RecordInfo expr
179-
fun i1 i2 i3 i4 -> new UpdateExpression<'Record>(uops.Apply(i1, i2, i3, i4))
179+
fun i1 i2 i3 i4 -> new UpdateExpression<'TRecord>(uops.Apply(i1, i2, i3, i4))
180180

181181
/// <summary>
182182
/// Precomputes a DynamoDB update expression using
@@ -185,14 +185,14 @@ type RecordTemplate<'Record> internal () =
185185
/// <param name="expr">Quoted record update operations.</param>
186186
member __.PrecomputeUpdateExpr(expr : Expr<'I1 -> 'I2 -> 'I3 -> 'I4 -> 'TRecord -> UpdateOp>) =
187187
let uops = UpdateOperations.ExtractOpExpr pickler.RecordInfo expr
188-
fun i1 i2 i3 i4 -> new UpdateExpression<'Record>(uops.Apply(i1, i2, i3, i4))
188+
fun i1 i2 i3 i4 -> new UpdateExpression<'TRecord>(uops.Apply(i1, i2, i3, i4))
189189

190190
/// Convert table key to attribute values
191191
member internal __.ToAttributeValues(key : TableKey) =
192192
KeyStructure.ExtractKey(keyStructure, key)
193193

194194
/// Converts a record instance to attribute values
195-
member internal __.ToAttributeValues(record : 'Record) =
195+
member internal __.ToAttributeValues(record : 'TRecord) =
196196
let kv = pickler.OfRecord record
197197

198198
match keyStructure with
@@ -211,6 +211,17 @@ type RecordTemplate<'Record> internal () =
211211
/// Constructs a record instance from attribute values
212212
member internal __.OfAttributeValues(ro : RestObject) = pickler.ToRecord ro
213213

214+
/// <summary>
215+
/// Generates a HashKey equality condition used for queries
216+
/// that match given table key. Useful for generating query
217+
/// conditions in records that specify a ConstantHashKey attribute.
218+
/// </summary>
219+
/// <param name="key">Key that specifies the required HashKey.</param>
220+
member __.GetHashKeyCondition(key : TableKey) =
221+
let av = __.ToAttributeValues(key).[keySchema.HashKey.AttributeName]
222+
let cond = mkHashKeyEqualityCondition keySchema av
223+
new ConditionExpression<'TRecord>(cond)
224+
214225
/// Record template factory methods
215226
[<Sealed; AbstractClass>]
216227
type RecordTemplate private () =

tests/FSharp.DynamoDB.Tests/ConditionalExpressionTests.fs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,15 @@ type ``Conditional Expression Tests`` () =
422422

423423
results.Length |> should equal 50
424424

425+
[<Fact>]
426+
let ``Extract Query expression from key`` () =
427+
let item = mkItem()
428+
let key = table.PutItem item
429+
let kc = table.Template.GetHashKeyCondition key
430+
let results = table.Query(kc)
431+
results.Length |> should equal 1
432+
results.[0] |> should equal item
433+
425434
[<Fact>]
426435
let ``Detect incompatible key conditions`` () =
427436
let test outcome q = table.Template.PrecomputeConditionalExpr(q).IsKeyConditionCompatible |> should equal outcome

0 commit comments

Comments
 (0)