Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
# Changelog for `FSharp.CosmosDb`
## [1.3.0] - Unreleased

- Updating to the latest version of Microsoft.Azure.Cosmos (3.35.4)
- Updating the Analyzer to the latest version of FSharp.Analyzers.SDK (0.14.1)

## [1.2.1] - 2022-11-22

Expand Down
2 changes: 1 addition & 1 deletion paket.dependencies
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ nuget Microsoft.Extensions.Configuration
nuget Microsoft.Extensions.Configuration.Json
nuget Expecto
nuget YoloDev.Expecto.TestSdk
nuget Microsoft.NET.Test.Sdk 16.8.3
nuget Microsoft.NET.Test.Sdk
nuget Microsoft.SourceLink.GitHub copy_local: true
nuget Microsoft.NETFramework.ReferenceAssemblies copy_local: true
nuget Microsoft.Build
Expand Down
1,122 changes: 464 additions & 658 deletions paket.lock

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions samples/FSharp.CosmosDb.Samples.ChangeFeed/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ let getFamiliesConnection host key =
[<EntryPoint>]
let main argv =
let environmentName =
System.Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")
Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")

let builder =
JsonConfigurationExtensions.AddJsonFile(
Expand All @@ -25,7 +25,7 @@ let main argv =
true,
true
),
sprintf "appsettings.%s.json" environmentName,
$"appsettings.%s{environmentName}.json",
true,
true
)
Expand All @@ -38,7 +38,7 @@ let main argv =
let conn = getFamiliesConnection host key

let onChange changes _ =
printfn "Changes: %A" changes
printfn $"Changes: %A{changes}"
System.Threading.Tasks.Task.CompletedTask

let processor =
Expand Down
12 changes: 6 additions & 6 deletions samples/FSharp.CosmosDb.Samples/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ let main argv =
true,
true
),
sprintf "appsettings.%s.json" environmentName,
$"appsettings.%s{environmentName}.json",
true,
true
)
Expand Down Expand Up @@ -117,33 +117,33 @@ let main argv =

do!
insert
|> AsyncSeq.iter (fun f -> printfn "Inserted: %A" f)
|> AsyncSeq.iter (fun f -> printfn $"Inserted: %A{f}")

let families = getFamilies conn

do!
families
|> AsyncSeq.iter (fun f -> printfn "Got: %A" f)
|> AsyncSeq.iter (fun f -> printfn $"Got: %A{f}")

let updatePowell = updateFamily conn "Powell.1" "Powell"

do!
updatePowell
|> AsyncSeq.iter (fun f -> printfn "Updated: %A" f)
|> AsyncSeq.iter (fun f -> printfn $"Updated: %A{f}")

let deletePowell = deleteFamily conn "Powell.1" "Powell"

do!
deletePowell
|> AsyncSeq.iter (fun f -> printfn "Deleted: %A" f)
|> AsyncSeq.iter (fun f -> printfn $"Deleted: %A{f}")

do!
conn
|> Cosmos.query<Family> "SELECT * FROM c"
|> Cosmos.execAsync
|> AsyncSeq.map (fun f -> { f with LastName = "Powellz" })
|> AsyncSeq.map (fun f -> conn |> Cosmos.replace f |> Cosmos.execAsync)
|> AsyncSeq.iter (fun f -> printfn "Replaced: %A" f)
|> AsyncSeq.iter (fun f -> printfn $"Replaced: %A{f}")

// do!
// conn
Expand Down
67 changes: 35 additions & 32 deletions src/FSharp.CosmosDb.Analyzer/Analyzer.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,43 @@ open FSharp.Analyzers.SDK
open FSharp.CosmosDb.Analyzer

[<Analyzer>]
let cosmosDbAnalyzer: Analyzer =
fun (context: Context) ->
let cosmosDbAnalyzer: Analyzer<EditorContext> =
fun (context: EditorContext) ->
let syntaxBlocks = CosmosCodeAnalysis.findOperations context

let connStr = ConnectionLookup.findConnectionString context.FileName

match connStr with
| Some connStr ->
match CosmosCodeAnalyzer.testConnection connStr with
| Error msg ->
[ for block in syntaxBlocks -> Messaging.error msg block.range ]
| Success client ->
syntaxBlocks
|> List.collect (fun block ->
match CosmosCodeAnalyzer.findDatabaseOperation block with
| Some(dbId, range) ->
CosmosCodeAnalyzer.analyzeDatabaseOperation dbId range client
|> List.append
(match CosmosCodeAnalyzer.findContainerOperation block with
| Some(containerName, range) ->
CosmosCodeAnalyzer.analyzeContainerNameOperation dbId containerName range client
| None -> [])
|> List.append
(match CosmosCodeAnalyzer.findParameters block with
| Some(parameters, range) -> CosmosCodeAnalyzer.analyzeParameters block parameters range
| None -> [])
let result =
match connStr with
| Some connStr ->
match CosmosCodeAnalyzer.testConnection connStr with
| Error msg ->
[ for block in syntaxBlocks -> Messaging.error msg block.range ]
| Success client ->
syntaxBlocks
|> List.collect (fun block ->
match CosmosCodeAnalyzer.findDatabaseOperation block with
| Some(dbId, range) ->
CosmosCodeAnalyzer.analyzeDatabaseOperation dbId range client
|> List.append
(match CosmosCodeAnalyzer.findContainerOperation block with
| Some(containerName, range) ->
CosmosCodeAnalyzer.analyzeContainerNameOperation dbId containerName range client
| None -> [])
|> List.append
(match CosmosCodeAnalyzer.findParameters block with
| Some(parameters, range) -> CosmosCodeAnalyzer.analyzeParameters block parameters range
| None -> [])

| None ->
match CosmosCodeAnalyzer.findParameters block with
| Some(parameters, range) -> CosmosCodeAnalyzer.analyzeParameters block parameters range
| None -> [])
|> List.distinctBy (fun msg -> msg.Range)
| None ->
[ for block in syntaxBlocks ->
Messaging.warning
"No connection string was found, ensure either the appropriate environment variables or appsettings.json is created"
block.range ]
async { return result }

| None ->
match CosmosCodeAnalyzer.findParameters block with
| Some(parameters, range) -> CosmosCodeAnalyzer.analyzeParameters block parameters range
| None -> [])
|> List.distinctBy (fun msg -> msg.Range)
| None ->
[ for block in syntaxBlocks ->
Messaging.warning
"No connection string was found, ensure either the appropriate environment variables or appsettings.json is created"
block.range ]
28 changes: 14 additions & 14 deletions src/FSharp.CosmosDb.Analyzer/ConnectionLookup.fs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ let private findFromEnv () =
let cs = gev "FSHARP_COSMOS_CONNSTR"

match host, key, cs with
| (Some host, Some key, None) ->
sprintf "AccountEndpoint=%s;AccountKey=%s;" host key
| Some host, Some key, None ->
$"AccountEndpoint=%s{host};AccountKey=%s{key};"
|> Some
| (None, None, cs) -> cs
| None, None, cs -> cs
| _ -> None

let private possibleFileNames =
Expand All @@ -41,7 +41,7 @@ type AppSettings =
let private findFromAppSettings relativeFile =
let folders =
[ Environment.CurrentDirectory
((FileInfo(relativeFile)).Directory).FullName ]
FileInfo(relativeFile).Directory.FullName ]

let settingsFiles =
possibleFileNames
Expand All @@ -68,11 +68,11 @@ let private findFromAppSettings relativeFile =
match config.CosmosConnection with
| Some cc ->
match cc.ConnectionString, cc.Host, cc.Key with
| (Some cs, None, None) when stringHasValue cs -> true
| (Some cs, Some _, Some _) when stringHasValue cs -> true
| (Some _, Some host, Some key) when stringHasValue host && stringHasValue key -> true
| (None, Some host, Some key) when stringHasValue host && stringHasValue key -> true
| (_, _, _) -> false
| Some cs, None, None when stringHasValue cs -> true
| Some cs, Some _, Some _ when stringHasValue cs -> true
| Some _, Some host, Some key when stringHasValue host && stringHasValue key -> true
| None, Some host, Some key when stringHasValue host && stringHasValue key -> true
| _, _, _ -> false
| None -> false)
|> List.tryHead

Expand All @@ -82,12 +82,12 @@ let private findFromAppSettings relativeFile =
match config.CosmosConnection with
| Some cc ->
match cc.ConnectionString, cc.Host, cc.Key with
| (Some cs, None, None) when stringHasValue cs -> Some cs
| (Some cs, Some _, Some _) when stringHasValue cs -> Some cs
| (Some _, Some host, Some key) when stringHasValue host && stringHasValue key ->
| Some cs, None, None when stringHasValue cs -> Some cs
| Some cs, Some _, Some _ when stringHasValue cs -> Some cs
| Some _, Some host, Some key when stringHasValue host && stringHasValue key ->
makeConnStr host key |> Some
| (None, Some host, Some key) when stringHasValue host && stringHasValue key -> makeConnStr host key |> Some
| (_, _, _) -> None
| None, Some host, Some key when stringHasValue host && stringHasValue key -> makeConnStr host key |> Some
| _, _, _ -> None
| None -> None

let findConnectionString relativeFile =
Expand Down
42 changes: 21 additions & 21 deletions src/FSharp.CosmosDb.Analyzer/CosmosCodeAnalysis.fs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ module CosmosCodeAnalysis =
let checkIfApply funcExpr argExpr range =
match funcExpr with
| SynExpr.Ident ident -> Some(ident.idText, argExpr, funcExpr.Range, range)
| SynExpr.LongIdent (_, LongIdentWithDots (listOfIds, _), _, _) ->
| SynExpr.LongIdent (_, SynLongIdent (listOfIds, _, _), _, _) ->
Some(dotConcat listOfIds, argExpr, funcExpr.Range, range)
| _ -> None

Expand All @@ -25,7 +25,7 @@ module CosmosCodeAnalysis =

let (|LongIdent|_|) =
function
| SynExpr.LongIdent (_, LongIdentWithDots (listOfIds, _), _, _) -> Some(dotConcat listOfIds, range)
| SynExpr.LongIdent (_, SynLongIdent (listOfIds, _, _), _, _) -> Some(dotConcat listOfIds, range)
| _ -> None

// for match of:
Expand All @@ -41,7 +41,7 @@ module CosmosCodeAnalysis =
// Cosmos.query query ...
let (|LiteralQuery|_|) =
function
| Apply ("Cosmos.query", SynExpr.Ident (identifier), funcRange, _) -> Some(identifier.idText, funcRange)
| Apply ("Cosmos.query", SynExpr.Ident identifier, funcRange, _) -> Some(identifier.idText, funcRange)
| _ -> None

// for match of:
Expand All @@ -50,7 +50,7 @@ module CosmosCodeAnalysis =
match synExpr with
| SynExpr.App (_,
_,
(SynExpr.TypeApp (SynExpr.LongIdent (_, LongIdentWithDots (listOfIds, _), _, _),
(SynExpr.TypeApp (SynExpr.LongIdent (_, SynLongIdent (listOfIds, _, _), _, _),
_,
typeNames,
_,
Expand All @@ -65,7 +65,7 @@ module CosmosCodeAnalysis =
typeNames
|> List.choose (fun typeName ->
match typeName with
| SynType.LongIdent (LongIdentWithDots (listOfIds, _)) -> dotConcat listOfIds |> Some
| SynType.LongIdent (SynLongIdent (listOfIds, _, _)) -> dotConcat listOfIds |> Some
| _ -> None)

Some(names, query, queryRange)
Expand All @@ -80,7 +80,7 @@ module CosmosCodeAnalysis =

let (|LiteralDatabase|_|) =
function
| Apply ("Cosmos.database", SynExpr.Ident (identifier), funcRange, _) -> Some(identifier.idText, funcRange)
| Apply ("Cosmos.database", SynExpr.Ident identifier, funcRange, _) -> Some(identifier.idText, funcRange)
| _ -> None

let (|Container|_|) =
Expand All @@ -91,7 +91,7 @@ module CosmosCodeAnalysis =

let (|LiteralContainer|_|) =
function
| Apply ("Cosmos.container", SynExpr.Ident (identifier), funcRange, _) -> Some(identifier.idText, funcRange)
| Apply ("Cosmos.container", SynExpr.Ident identifier, funcRange, _) -> Some(identifier.idText, funcRange)
| _ -> None

let (|ParameterTuple|_|) =
Expand All @@ -102,13 +102,13 @@ module CosmosCodeAnalysis =
_,
_) -> Some(parameterName, paramRange, funcName, funcRange, Some appRange)
| SynExpr.Tuple (_,
[ SynExpr.Const (SynConst.String (parameterName, _, paramRange), constRange); secondItem ],
[ SynExpr.Const (SynConst.String (parameterName, _, paramRange), _); secondItem ],
_,
_) ->
match secondItem with
| SynExpr.LongIdent (_, longDotId, _, identRange) ->
match longDotId with
| LongIdentWithDots (listOfIds, _) ->
| SynLongIdent (listOfIds, _, _) ->
let fullName =
listOfIds
|> List.map (fun id -> id.idText)
Expand All @@ -117,10 +117,10 @@ module CosmosCodeAnalysis =
Some(parameterName, paramRange, fullName, identRange, None)
| _ -> None
| SynExpr.Tuple (_, [ firstItem; secondItem ], _, _) ->
printfn "Tuple: %A %A" firstItem secondItem
printfn $"Tuple: %A{firstItem} %A{secondItem}"
None
| x ->
printfn "No idea: %A" x
printfn $"No idea: %A{x}"
None

let rec readParameters =
Expand Down Expand Up @@ -191,11 +191,11 @@ module CosmosCodeAnalysis =

// This represents the "tail" of our AST, so we match on all the ways that it could end
// and then walk backwards from there to find the other parts that should exist
let rec visitSyntacticExpression (expr: SynExpr) (fullExpressionRange: range) =
let rec visitSyntacticExpression (expr: SynExpr) =
match expr with
| SynExpr.App (_, _, funcExpr, argExpr, range) ->
match argExpr with
| Apply (("Cosmos.execAsync"), _, _, _) ->
| Apply ("Cosmos.execAsync", _, _, _) ->
let blocks =
[ yield! findQuery funcExpr
yield! findDatabase funcExpr
Expand All @@ -204,7 +204,7 @@ module CosmosCodeAnalysis =

[ { blocks = blocks; range = range } ]

| LongIdent (("Cosmos.execAsync"), appRange) ->
| LongIdent ("Cosmos.execAsync", _) ->
let blocks =
[ yield! findQuery funcExpr
yield! findDatabase funcExpr
Expand Down Expand Up @@ -266,28 +266,28 @@ module CosmosCodeAnalysis =

| _ -> []

| SynExpr.LetOrUse (_, _, bindings, body, range, _) ->
[ yield! visitSyntacticExpression body range
| SynExpr.LetOrUse (_, _, bindings, body, _, _) ->
[ yield! visitSyntacticExpression body
for binding in bindings do
yield! visitBinding binding ]

| _ -> []

and visitBinding (binding: SynBinding) : CosmosOperation list =
match binding with
| SynBinding (_, _, _, _, _, _, _, _, _, expr, range, _, _) -> visitSyntacticExpression expr range
| SynBinding (_, _, _, _, _, _, _, _, _, expr, _, _, _) -> visitSyntacticExpression expr


let findOperations (ctx: Context) =
let findOperations (ctx: EditorContext) =
let operations = ResizeArray<CosmosOperation>()

match ctx.ParseTree with
match ctx.ParseFileResults.ParseTree with
| ParsedInput.ImplFile input ->
match input with
| ParsedImplFileInput (_, _, _, _, _, modules, _, _) ->
| ParsedImplFileInput (_, _, _, _, _, modules, _, _, _) ->
for parsedModule in modules do
match parsedModule with
| SynModuleOrNamespace (_, _, _, declarations, _, _, _, _) ->
| SynModuleOrNamespace (_, _, _, declarations, _, _, _, _, _) ->
for declaration in declarations do
match declaration with
| SynModuleDecl.Let (_, bindings, _) ->
Expand Down
Loading