Skip to content

Commit ef0f176

Browse files
committed
fixing analyser to support generics earlier on
1 parent e15e8b8 commit ef0f176

4 files changed

Lines changed: 88 additions & 36 deletions

File tree

.editorconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[*.fs]
2+
indent_size=4
3+
max_line_length=150

src/FSharp.CosmosDb.Analyzer/CosmosCodeAnalysis.fs

Lines changed: 53 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -50,48 +50,81 @@ module CosmosCodeAnalysis =
5050

5151
let (|Query|_|) =
5252
function
53-
| Apply ("Cosmos.query", SynExpr.Const (SynConst.String (query, queryRange), constRange), range, appRange) ->
54-
Some(query, constRange)
53+
| Apply ("Cosmos.query", SynExpr.Const (SynConst.String (query, queryRange), constRange), range, appRange) -> Some(query, constRange)
5554
| _ -> None
5655

5756
let (|LiteralQuery|_|) =
5857
function
5958
| Apply ("Cosmos.query", SynExpr.Ident (identifier), funcRange, appRange) -> Some(identifier.idText, funcRange)
6059
| _ -> None
6160

61+
let (|TypedQuery|_|) =
62+
function
63+
| SynExpr.App (exprAtomic,
64+
isInfix,
65+
(SynExpr.TypeApp (funcExpr, lessRange, typeNames, commasRange, greaterRange, typeArgsRange, typeAppRange)),
66+
SynExpr.Const (SynConst.String (query, queryRange), constRange),
67+
appRange) ->
68+
match funcExpr with
69+
| SynExpr.LongIdent (isOptional, longDotId, altName, identRange) ->
70+
match longDotId with
71+
| LongIdentWithDots (listOfIds, ranges) ->
72+
let fullName =
73+
listOfIds
74+
|> List.map (fun id -> id.idText)
75+
|> String.concat "."
76+
77+
match fullName with
78+
| "Cosmos.query" ->
79+
let names =
80+
typeNames
81+
|> List.filter (fun typeName ->
82+
match typeName with
83+
| SynType.LongIdent (_) -> true
84+
| _ -> false)
85+
|> List.map (fun typeName ->
86+
match typeName with
87+
| SynType.LongIdent (dots) ->
88+
match dots with
89+
| LongIdentWithDots (listOfIds, _) ->
90+
listOfIds
91+
|> List.map (fun id -> id.idText)
92+
|> String.concat "."
93+
| _ -> "")
94+
95+
Some(names, query, typeAppRange)
96+
| _ -> None
97+
| _ -> None
98+
| _ -> None
99+
62100
let (|Database|_|) =
63101
function
64-
| Apply ("Cosmos.database", SynExpr.Const (SynConst.String (dbId, queryRange), constRange), range, appRange) ->
65-
Some(dbId, constRange)
102+
| Apply ("Cosmos.database", SynExpr.Const (SynConst.String (dbId, queryRange), constRange), range, appRange) -> Some(dbId, constRange)
66103
| _ -> None
67104

68105
let (|LiteralDatabase|_|) =
69106
function
70-
| Apply ("Cosmos.database", SynExpr.Ident (identifier), funcRange, appRange) ->
71-
Some(identifier.idText, funcRange)
107+
| Apply ("Cosmos.database", SynExpr.Ident (identifier), funcRange, appRange) -> Some(identifier.idText, funcRange)
72108
| _ -> None
73109

74110
let (|Container|_|) =
75111
function
76-
| Apply ("Cosmos.container", SynExpr.Const (SynConst.String (containerName, queryRange), constRange), range,
77-
appRange) -> Some(containerName, constRange)
112+
| Apply ("Cosmos.container", SynExpr.Const (SynConst.String (containerName, queryRange), constRange), range, appRange) ->
113+
Some(containerName, constRange)
78114
| _ -> None
79115

80116
let (|LiteralContainer|_|) =
81117
function
82-
| Apply ("Cosmos.container", SynExpr.Ident (identifier), funcRange, appRange) ->
83-
Some(identifier.idText, funcRange)
118+
| Apply ("Cosmos.container", SynExpr.Ident (identifier), funcRange, appRange) -> Some(identifier.idText, funcRange)
84119
| _ -> None
85120

86121
let (|ParameterTuple|_|) =
87122
function
88123
| SynExpr.Tuple (isStruct,
89-
[ SynExpr.Const (SynConst.String (parameterName, paramRange), constRange);
90-
Apply (funcName, exprArgs, funcRange, appRange) ], commaRange, tupleRange) ->
91-
Some(parameterName, paramRange, funcName, funcRange, Some appRange)
92-
| SynExpr.Tuple (isStruct,
93-
[ SynExpr.Const (SynConst.String (parameterName, paramRange), constRange); secondItem ],
94-
commaRange, tupleRange) ->
124+
[ SynExpr.Const (SynConst.String (parameterName, paramRange), constRange); Apply (funcName, exprArgs, funcRange, appRange) ],
125+
commaRange,
126+
tupleRange) -> Some(parameterName, paramRange, funcName, funcRange, Some appRange)
127+
| SynExpr.Tuple (isStruct, [ SynExpr.Const (SynConst.String (parameterName, paramRange), constRange); secondItem ], commaRange, tupleRange) ->
95128
match secondItem with
96129
| SynExpr.LongIdent (isOptional, longDotId, altName, identRange) ->
97130
match longDotId with
@@ -122,15 +155,15 @@ module CosmosCodeAnalysis =
122155
function
123156
| Apply ("Cosmos.parameters", SynExpr.ArrayOrListOfSeqExpr (isArray, listExpr, listRange), funcRange, appRange) ->
124157
match listExpr with
125-
| SynExpr.CompExpr (isArrayOfList, isNotNakedRefCell, compExpr, compRange) ->
126-
Some(readParameters compExpr, compRange)
158+
| SynExpr.CompExpr (isArrayOfList, isNotNakedRefCell, compExpr, compRange) -> Some(readParameters compExpr, compRange)
127159
| _ -> None
128160
| _ -> None
129161

130162
let rec findQuery =
131163
function
132164
| Query (query, range) -> [ CosmosAnalyzerBlock.Query(query, range) ]
133165
| LiteralQuery (identifier, range) -> [ CosmosAnalyzerBlock.LiteralQuery(identifier, range) ]
166+
| TypedQuery (typeNames, query, typeAppRange) -> [ CosmosAnalyzerBlock.Query(query, typeAppRange) ]
134167
| SynExpr.App (exprAtomic, isInfix, funcExpr, argExpr, range) ->
135168
[ yield! findQuery funcExpr
136169
yield! findQuery argExpr ]
@@ -262,8 +295,8 @@ module CosmosCodeAnalysis =
262295

263296
and visitBinding (binding: SynBinding): CosmosOperation list =
264297
match binding with
265-
| SynBinding.Binding (access, kind, mustInline, isMutable, attrs, xmlDecl, valData, headPat, returnInfo, expr,
266-
range, seqPoint) -> visitSyntacticExpression expr range
298+
| SynBinding.Binding (access, kind, mustInline, isMutable, attrs, xmlDecl, valData, headPat, returnInfo, expr, range, seqPoint) ->
299+
visitSyntacticExpression expr range
267300

268301

269302
let findOperations (ctx: Context) =

tests/FSharp.CosmosDb.Analyzer.Tests/Program.fs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
open Expecto
44
open Expecto.Logging
55

6-
let config = { defaultConfig with verbosity = Verbose }
6+
let config =
7+
{ defaultConfig with
8+
verbosity = Verbose
9+
``parallel`` = false }
710

811
[<EntryPoint>]
912
let main argv = runTestsInAssembly config argv

tests/FSharp.CosmosDb.Analyzer.Tests/QueryTests.fs

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,25 @@ open FSharp.CosmosDb.Analyzer
66

77
[<Tests>]
88
let tests =
9-
testList "Query API can be analyzed"
9+
testList
10+
"Query API can be analyzed"
1011
[ test "Finds all the operations in a file" {
1112
match context (find "../samples/querySample.fs") with
1213
| None -> failwith "Could not load test script"
1314
| Some context ->
14-
let ops = CosmosCodeAnalysis.findOperations context
15+
let ops =
16+
CosmosCodeAnalysis.findOperations context
17+
1518
Expect.equal 1 (List.length ops) "Found one operation block"
1619
}
1720

1821
test "Found operation should have 3 analysable bits" {
1922
match context (find "../samples/querySample.fs") with
2023
| None -> failwith "Could not load test script"
2124
| Some context ->
22-
let ops = CosmosCodeAnalysis.findOperations context
25+
let ops =
26+
CosmosCodeAnalysis.findOperations context
27+
2328
let head = List.exactlyOne ops
2429
Expect.equal 4 (List.length head.blocks) "Found four things to analyse"
2530
}
@@ -28,16 +33,18 @@ let tests =
2833
match context (find "../samples/querySample.fs") with
2934
| None -> failwith "Could not load test script"
3035
| Some context ->
31-
let ops = CosmosCodeAnalysis.findOperations context
36+
let ops =
37+
CosmosCodeAnalysis.findOperations context
38+
3239
let head = List.exactlyOne ops
3340

3441
let query =
3542
head.blocks
3643
|> List.tryFind (function
37-
| CosmosAnalyzerBlock.Query(_) -> true
44+
| CosmosAnalyzerBlock.Query (_) -> true
3845
| _ -> false)
3946
|> Option.map (function
40-
| CosmosAnalyzerBlock.Query(query, range) -> query
47+
| CosmosAnalyzerBlock.Query (query, range) -> query
4148
| _ -> failwith "Should've found the query operation")
4249

4350
Expect.equal "SELECT * FROM u WHERE u.Name = @name" query.Value "Query matches the one in code"
@@ -47,16 +54,18 @@ let tests =
4754
match context (find "../samples/querySample.fs") with
4855
| None -> failwith "Could not load test script"
4956
| Some context ->
50-
let ops = CosmosCodeAnalysis.findOperations context
57+
let ops =
58+
CosmosCodeAnalysis.findOperations context
59+
5160
let head = List.exactlyOne ops
5261

5362
let dbId =
5463
head.blocks
5564
|> List.tryFind (function
56-
| CosmosAnalyzerBlock.DatabaseId(_) -> true
65+
| CosmosAnalyzerBlock.DatabaseId (_) -> true
5766
| _ -> false)
5867
|> Option.map (function
59-
| CosmosAnalyzerBlock.DatabaseId(dbId, _) -> dbId
68+
| CosmosAnalyzerBlock.DatabaseId (dbId, _) -> dbId
6069
| _ -> failwith "Should've found the DatabaseId operation")
6170

6271
Expect.equal "UserDb" dbId.Value "DatabaseId matches the one in code"
@@ -66,16 +75,18 @@ let tests =
6675
match context (find "../samples/querySample.fs") with
6776
| None -> failwith "Could not load test script"
6877
| Some context ->
69-
let ops = CosmosCodeAnalysis.findOperations context
78+
let ops =
79+
CosmosCodeAnalysis.findOperations context
80+
7081
let head = List.exactlyOne ops
7182

7283
let container =
7384
head.blocks
7485
|> List.tryFind (function
75-
| CosmosAnalyzerBlock.ContainerName(_) -> true
86+
| CosmosAnalyzerBlock.ContainerName (_) -> true
7687
| _ -> false)
7788
|> Option.map (function
78-
| CosmosAnalyzerBlock.ContainerName(containerName, _) -> containerName
89+
| CosmosAnalyzerBlock.ContainerName (containerName, _) -> containerName
7990
| _ -> failwith "Should've found the ContainerName operation")
8091

8192
Expect.equal "UserContainer" container.Value "ContainerName matches the one in code"
@@ -85,16 +96,18 @@ let tests =
8596
match context (find "../samples/querySample.fs") with
8697
| None -> failwith "Could not load test script"
8798
| Some context ->
88-
let ops = CosmosCodeAnalysis.findOperations context
99+
let ops =
100+
CosmosCodeAnalysis.findOperations context
101+
89102
let head = List.exactlyOne ops
90103

91104
let parameters =
92105
head.blocks
93106
|> List.tryFind (function
94-
| CosmosAnalyzerBlock.Parameters(_) -> true
107+
| CosmosAnalyzerBlock.Parameters (_) -> true
95108
| _ -> false)
96109
|> Option.map (function
97-
| CosmosAnalyzerBlock.Parameters(parameters, _) -> parameters
110+
| CosmosAnalyzerBlock.Parameters (parameters, _) -> parameters
98111
| _ -> failwith "Should've found the Parameters operation")
99112

100113
match parameters with

0 commit comments

Comments
 (0)