Skip to content

Commit 822f757

Browse files
committed
Merge branch 'add_deleteContainer_operation'
2 parents 7b9d5ae + 77675d3 commit 822f757

5 files changed

Lines changed: 207 additions & 65 deletions

File tree

README.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,9 @@ let main argv =
100100
} |> Async.RunSynchronously
101101
```
102102

103-
### Delete
103+
### DeleteItem
104104

105-
```fsharp
105+
```f#
106106
open FSharp.CosmosDb
107107
108108
let connStr = "..."
@@ -116,6 +116,19 @@ let updateUser id partitionKey =
116116
|> Cosmos.execAsync
117117
```
118118

119+
### DeleteContainer
120+
```f#
121+
open FSharp.CosmosDb
122+
123+
let connStr = "..."
124+
125+
connStr
126+
|> Cosmos.container "ContainerName"
127+
|> Cosmos.deleteContainer
128+
|> Cosmos.execAsync
129+
|> Async.Ignore
130+
```
131+
119132
# FSharp.CosmosDb.Analyzer 💡
120133

121134
[![NuGet Badge - FSharp.CosmosDb](https://buildstats.info/nuget/FSharp.CosmosDb)](https://www.nuget.org/packages/FSharp.CosmosDb)

samples/FSharp.CosmosDb.Samples/Program.fs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ let updateFamily conn id pk =
5050

5151
let deleteFamily conn id pk =
5252
conn
53-
|> Cosmos.delete<Family> id pk
53+
|> Cosmos.deleteItem<Family> id pk
5454
|> Cosmos.execAsync
5555

5656
[<EntryPoint>]
@@ -131,6 +131,20 @@ let main argv =
131131
|> AsyncSeq.map (fun f -> { f with LastName = "Powellz" })
132132
|> AsyncSeq.map (fun f -> conn |> Cosmos.replace f |> Cosmos.execAsync)
133133
|> AsyncSeq.iter (fun f -> printfn "Replaced: %A" f)
134+
135+
do!
136+
conn
137+
|> Cosmos.container "Family"
138+
|> Cosmos.deleteContainer
139+
|> Cosmos.execAsync
140+
|> Async.Ignore
141+
142+
do!
143+
conn
144+
|> Cosmos.container "Family"
145+
|> Cosmos.deleteContainerIfExists
146+
|> Cosmos.execAsync
147+
|> Async.Ignore
134148

135149
return 0 // return an integer exit code
136150
}

src/FSharp.CosmosDb/Cosmos.fs

Lines changed: 65 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -47,89 +47,89 @@ module Cosmos =
4747
Query = None
4848
Parameters = [] }
4949

50-
let query<'T> query op : ContainerOperation<'T> =
51-
Query
52-
{ defaultQueryOp () with
53-
Query = Some query
54-
Connection = op }
50+
let query<'T> query op : QueryOp<'T> =
51+
{ defaultQueryOp () with
52+
Query = Some query
53+
Connection = op }
5554

5655
let parameters arr op =
57-
match op with
58-
| Query q ->
59-
Query
60-
{ q with
61-
Parameters = q.Parameters @ arr }
62-
| _ -> failwith "Only the Query discriminated union supports parameters"
56+
{ op with QueryOp.Parameters = op.Parameters @ arr }
57+
58+
// --- DATABASE EXISTS --- //
59+
let databaseExists<'T> op =
60+
{ CheckIfDatabaseExistsOp.Connection = op }
6361

6462
// --- INSERT --- //
6563

6664
let insertMany<'T> (values: 'T list) op =
67-
Insert { Connection = op; Values = values }
65+
{ InsertOp.Connection = op; Values = values }
6866

6967
let insert<'T> (value: 'T) op =
70-
Insert { Connection = op; Values = [ value ] }
68+
{ InsertOp.Connection = op; Values = [ value ] }
7169

7270
// --- INSERT --- //
7371

7472
let upsertMany<'T> (values: 'T list) op =
75-
Upsert { Connection = op; Values = values }
73+
{ UpsertOp.Connection = op; Values = values }
7674

7775
let upsert<'T> (value: 'T) op =
78-
Upsert { Connection = op; Values = [ value ] }
76+
{ UpsertOp.Connection = op; Values = [ value ] }
7977

8078
// --- UPDATE --- //
8179

8280
let update<'T> id partitionKey (updater: 'T -> 'T) op =
83-
Update
84-
{ Connection = op
85-
Id = id
86-
PartitionKey = partitionKey
87-
Updater = updater }
88-
89-
// --- DELETE --- //
90-
91-
let delete<'T> id partitionKey op =
92-
Delete
93-
{ Connection = op
94-
Id = id
95-
PartitionKey = partitionKey }
81+
{ UpdateOp.Connection = op
82+
Id = id
83+
PartitionKey = partitionKey
84+
Updater = updater }
85+
86+
// --- DELETE ITEM --- //
87+
88+
let deleteItem<'T> id partitionKey op =
89+
{ DeleteItemOp.Connection = op
90+
Id = id
91+
PartitionKey = partitionKey }
92+
93+
// --- GET CONTAINER PROPERTIES --- //
94+
let getContainerProperties op =
95+
{ GetContainerPropertiesOp.Connection = op }
96+
97+
// --- CONTAINER EXISTS --- //
98+
let containerExists op =
99+
{ CheckIfContainerExistsOp.Connection = op }
100+
101+
// --- DELETE CONTAINER --- //
102+
103+
let deleteContainer<'T> op : DeleteContainerOp<'T> =
104+
{ DeleteContainerOp.Connection = op }
105+
106+
// --- DELETE CONTAINER IF EXISTS --- //
107+
108+
let deleteContainerIfExists op : DeleteContainerIfExistsOp =
109+
{ DeleteContainerIfExistsOp.Connection = op }
96110

97111
// --- READ --- //
98112

99113
let read id partitionKey op =
100-
Read
101-
{ Connection = op
102-
Id = id
103-
PartitionKey = partitionKey }
114+
{ ReadOp.Connection = op
115+
Id = id
116+
PartitionKey = partitionKey }
104117

105118
// --- REPLACE --- //
106119

107120
let replace<'T> (item: 'T) op =
108-
Replace { Connection = op; Item = item }
121+
{ ReplaceOp.Connection = op; Item = item }
109122

110123
// --- Execute --- //
111124

112125
let private getClient (connInfo: ConnectionOperation) = connInfo.GetClient()
113126

114127
let dispose (connInfo: ConnectionOperation) = (connInfo :> IDisposable).Dispose()
115128

116-
let execAsync<'T> (op: ContainerOperation<'T>) =
117-
match op with
118-
| Query op -> OperationHandling.execQuery getClient op
119-
| Insert op -> OperationHandling.execInsert getClient op
120-
| Update op -> OperationHandling.execUpdate getClient op
121-
| Delete op -> OperationHandling.execDelete getClient op
122-
| Upsert op -> OperationHandling.execUpsert getClient op
123-
| Read op -> OperationHandling.execRead getClient op
124-
| Replace op -> OperationHandling.execReplace getClient op
125-
126-
let execBatchAsync<'T> batchSize (op: ContainerOperation<'T>) =
127-
match op with
128-
| Query op ->
129-
let queryOps = QueryRequestOptions()
130-
queryOps.MaxItemCount <- batchSize
131-
OperationHandling.execQueryBatch getClient op queryOps
132-
| _ -> failwith "Batch return operation only supported with query operations, use `execAsync` instead."
129+
let execBatchAsync<'T> batchSize op =
130+
let queryOps = QueryRequestOptions()
131+
queryOps.MaxItemCount <- batchSize
132+
OperationHandling.execQueryBatch getClient op queryOps
133133

134134
// --- Access Cosmos APIs directly --- //
135135

@@ -233,3 +233,18 @@ module Cosmos =
233233
processor.Build()
234234
| None ->
235235
failwith "Unable to connect the change feed. Ensure the container and lease container info is all set"
236+
237+
type Cosmos =
238+
static member private getClient (connInfo: ConnectionOperation) = connInfo.GetClient()
239+
static member execAsync (op: QueryOp<'T>) = OperationHandling.execQuery Cosmos.getClient op
240+
static member execAsync op = OperationHandling.execCheckIfDatabaseExists Cosmos.getClient op
241+
static member execAsync op = OperationHandling.execInsert Cosmos.getClient op
242+
static member execAsync op = OperationHandling.execUpdate Cosmos.getClient op
243+
static member execAsync op = OperationHandling.execDeleteItem Cosmos.getClient op
244+
static member execAsync op = OperationHandling.execGetContainerProperties Cosmos.getClient op
245+
static member execAsync op = OperationHandling.execCheckIfContainerExists Cosmos.getClient op
246+
static member execAsync op = OperationHandling.execDeleteContainer Cosmos.getClient op
247+
static member execAsync op = OperationHandling.execDeleteContainerIfExists Cosmos.getClient op
248+
static member execAsync op = OperationHandling.execUpsert Cosmos.getClient op
249+
static member execAsync op = OperationHandling.execRead Cosmos.getClient op
250+
static member execAsync op = OperationHandling.execReplace Cosmos.getClient op

src/FSharp.CosmosDb/OperationHandling.fs

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,29 @@ let execQueryBatch (getClient: ConnectionOperation -> CosmosClient) (op: QueryOp
6666
| Some result -> result |> AsyncSeq.ofAsyncFeedIterator
6767
| None ->
6868
failwith "Unable to construct a query as some values are missing across the database, container name and query"
69+
70+
let execCheckIfDatabaseExists (getClient: ConnectionOperation -> CosmosClient) (op: CheckIfDatabaseExistsOp) =
71+
let connInfo = op.Connection
72+
let client = getClient connInfo
73+
74+
use iterator = client.GetDatabaseQueryIterator<DatabaseProperties>()
75+
76+
match connInfo.DatabaseId with
77+
| Some databaseId ->
78+
iterator
79+
|> AsyncSeq.unfold (fun t ->
80+
if iterator.HasMoreResults then
81+
Some (iterator.ReadNextAsync(), iterator)
82+
else
83+
None)
84+
|> AsyncSeq.collect (fun i ->
85+
asyncSeq {
86+
let! c = i |> Async.AwaitTask
87+
for x in c do
88+
yield x
89+
})
90+
|> AsyncSeq.exists (fun i -> i.Id = databaseId)
91+
| None -> failwith "failed to check if database exists"
6992

7093
let execInsert (getClient: ConnectionOperation -> CosmosClient) (op: InsertOp<'T>) =
7194
let connInfo = op.Connection
@@ -189,7 +212,7 @@ let execUpdate (getClient: ConnectionOperation -> CosmosClient) (op: UpdateOp<'T
189212

190213
| None -> failwith "Unable to read from the container to get the item for updating"
191214

192-
let execDelete (getClient: ConnectionOperation -> CosmosClient) (op: DeleteOp<'T>) =
215+
let execDeleteItem (getClient: ConnectionOperation -> CosmosClient) (op: DeleteItemOp<'T>) =
193216
let connInfo = op.Connection
194217
let client = getClient connInfo
195218

@@ -216,7 +239,77 @@ let execDelete (getClient: ConnectionOperation -> CosmosClient) (op: DeleteOp<'T
216239
|> AsyncSeq.ofSeqAsync
217240

218241
| None -> failwith "Unable to read from the container to get the item for updating"
242+
243+
let execGetContainerProperties (getClient: ConnectionOperation -> CosmosClient) (op: GetContainerPropertiesOp) =
244+
let connInfo = op.Connection
245+
let client = getClient connInfo
246+
247+
let containerName =
248+
match connInfo.ContainerName with
249+
| None -> failwith "ContainerName is not provided"
250+
| Some containerName -> containerName
251+
252+
use iterator =
253+
match connInfo.DatabaseId with
254+
| None -> failwith "DatabaseId is not provided"
255+
| Some databaseId ->
256+
client
257+
.GetDatabase(databaseId)
258+
.GetContainerQueryIterator<ContainerProperties>()
259+
260+
iterator
261+
|> AsyncSeq.unfold (fun t ->
262+
if iterator.HasMoreResults then
263+
Some (iterator.ReadNextAsync(), iterator)
264+
else
265+
None)
266+
|> AsyncSeq.collect (fun i ->
267+
asyncSeq {
268+
let! c = i |> Async.AwaitTask
269+
for x in c do
270+
yield x
271+
})
272+
|> AsyncSeq.tryFind (fun i -> i.Id = containerName)
273+
274+
let execCheckIfContainerExists (getClient: ConnectionOperation -> CosmosClient) (op: CheckIfContainerExistsOp) =
275+
async {
276+
let! containerProperties = execGetContainerProperties getClient { Connection= op.Connection }
277+
278+
return containerProperties
279+
|> Option.isSome
280+
}
281+
282+
let execDeleteContainer (getClient: ConnectionOperation -> CosmosClient) (op: DeleteContainerOp<'T>) =
283+
let connInfo = op.Connection
284+
let client = getClient connInfo
219285

286+
let result =
287+
maybe {
288+
let! databaseId = connInfo.DatabaseId
289+
let! containerName = connInfo.ContainerName
290+
291+
let db = client.GetDatabase databaseId
292+
293+
let container = db.GetContainer containerName
294+
295+
return
296+
container.DeleteContainerAsync ()
297+
|> Async.AwaitTask
298+
}
299+
300+
match result with
301+
| Some result -> result
302+
| None -> failwith "Unable to delete container"
303+
304+
let execDeleteContainerIfExists (getClient: ConnectionOperation -> CosmosClient) (op: DeleteContainerIfExistsOp) =
305+
async {
306+
let! databaseExists = execCheckIfDatabaseExists getClient { Connection= op.Connection }
307+
let! containerExists = execCheckIfContainerExists getClient { Connection= op.Connection }
308+
if databaseExists && containerExists then
309+
do! execDeleteContainer getClient { Connection= op.Connection }
310+
|> Async.Ignore
311+
}
312+
220313
let execRead (getClient: ConnectionOperation -> CosmosClient) (op: ReadOp<'T>) =
221314
let connInfo = op.Connection
222315
let client = getClient connInfo

src/FSharp.CosmosDb/Types.fs

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
namespace FSharp.CosmosDb
22

3+
open FSharp.CosmosDb
34
open Microsoft.Azure.Cosmos
45
open System.Threading
56
open System.Threading.Tasks
@@ -86,6 +87,9 @@ type QueryOp<'T> =
8687
Query: string option
8788
Parameters: (string * obj) list }
8889

90+
type CheckIfDatabaseExistsOp =
91+
{ Connection: ConnectionOperation }
92+
8993
type InsertOp<'T> =
9094
{ Connection: ConnectionOperation
9195
Values: 'T list }
@@ -100,11 +104,23 @@ type UpdateOp<'T> =
100104
PartitionKey: string
101105
Updater: 'T -> 'T }
102106

103-
type DeleteOp<'T> =
107+
type DeleteItemOp<'T> =
104108
{ Connection: ConnectionOperation
105109
Id: string
106110
PartitionKey: string }
107-
111+
112+
type GetContainerPropertiesOp =
113+
{ Connection: ConnectionOperation }
114+
115+
type CheckIfContainerExistsOp =
116+
{ Connection: ConnectionOperation }
117+
118+
type DeleteContainerOp<'T> =
119+
{ Connection: ConnectionOperation }
120+
121+
type DeleteContainerIfExistsOp =
122+
{ Connection: ConnectionOperation }
123+
108124
type ReadOp<'T> =
109125
{ Connection: ConnectionOperation
110126
Id: string
@@ -114,15 +130,6 @@ type ReplaceOp<'T> =
114130
{ Connection: ConnectionOperation
115131
Item: 'T }
116132

117-
type ContainerOperation<'T> =
118-
| Query of QueryOp<'T>
119-
| Insert of InsertOp<'T>
120-
| Update of UpdateOp<'T>
121-
| Delete of DeleteOp<'T>
122-
| Upsert of UpsertOp<'T>
123-
| Read of ReadOp<'T>
124-
| Replace of ReplaceOp<'T>
125-
126133
type ChangeFeedOptions<'T> =
127134
{ Connection: ConnectionOperation
128135
Processor: string

0 commit comments

Comments
 (0)