Skip to content

Commit 140a86c

Browse files
authored
Merge pull request #3 from johnberzy-bazinga/dependencies2
Dependencies
2 parents 875ac58 + 71fd3b9 commit 140a86c

20 files changed

+405
-132
lines changed

samples/FSharp.Data.GraphQL.Samples.GiraffeServer/FSharp.Data.GraphQL.Samples.GiraffeServer.fsproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
<Import Project="..\..\netfx.props" />
23
<PropertyGroup>
34
<TargetFramework>netcoreapp2.1</TargetFramework>
45
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>

samples/client-provider/short_hand_query.fsx

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,27 @@
1212
// #r "../../src/FSharp.Data.GraphQL.Client/bin/Debug/net461/FSharp.Data.GraphQL.Client.dll"
1313

1414
// Uncomment those to use dotnet build command for the client assembly using netstandard2.0
15-
#r "../../src/FSharp.Data.GraphQL.Client/bin/Debug/netstandard2.0/FSharp.Data.GraphQL.Shared.dll"
16-
#r "../../src/FSharp.Data.GraphQL.Client/bin/Debug/netstandard2.0/FSharp.Data.GraphQL.Client.dll"
17-
#r "../../src/FSharp.Data.GraphQL.Client/bin/Debug/typeproviders/fsharp41/net461/netstandard.dll"
15+
#r "../../src/FSharp.Data.GraphQL.Client/bin/Release/netstandard2.0/FSharp.Data.GraphQL.Shared.dll"
16+
#r "../../src/FSharp.Data.GraphQL.Client/bin/Release/netstandard2.0/FSharp.Data.GraphQL.Client.dll"
17+
#r "../../src/FSharp.Data.GraphQL.Client/bin/Release/typeproviders/fsharp41/net461/netstandard.dll"
1818

1919
open FSharp.Data.GraphQL
2020

2121
type MyProvider = GraphQLProvider<"sample_schema.json">
2222

23-
let operation =
24-
MyProvider.Operation<"""{
25-
hero(id: "1000") {
23+
let o =
24+
MyProvider.Operation<"""query Foo ($id2:Int) {
25+
hero {
2626
name
2727
}
2828
}""">()
2929

30-
let runtimeContext = MyProvider.GetContext(serverUrl = "http://localhost:8084")
31-
32-
let result = operation.Run(runtimeContext)
30+
let o =
31+
MyProvider.Operation<"""query Foo ($id2:String) {
32+
hero {
33+
name
34+
}
35+
}""">()
3336

34-
// Query result objects have pretty-printing and structural equality.
35-
printfn "Data: %A\n" result.Data
36-
printfn "Errors: %A\n" result.Errors
37-
printfn "Custom data: %A\n" result.CustomData
37+
let runtimeContext = MyProvider.GetContext(serverUrl = "http://localhost:8084")
38+
o.Run()

samples/client-provider/standard_features.fsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@
1212
// #r "../../src/FSharp.Data.GraphQL.Client/bin/Debug/net461/FSharp.Data.GraphQL.Client.dll"
1313

1414
// Uncomment those to use dotnet build command for the client assembly using netstandard2.0
15-
#r "../../src/FSharp.Data.GraphQL.Client/bin/Debug/netstandard2.0/FSharp.Data.GraphQL.Shared.dll"
16-
#r "../../src/FSharp.Data.GraphQL.Client/bin/Debug/netstandard2.0/FSharp.Data.GraphQL.Client.dll"
17-
#r "../../src/FSharp.Data.GraphQL.Client/bin/Debug/typeproviders/fsharp41/net461/netstandard.dll"
15+
#r "../../src/FSharp.Data.GraphQL.Client/bin/Release/netstandard2.0/FSharp.Data.GraphQL.Shared.dll"
16+
#r "../../src/FSharp.Data.GraphQL.Client/bin/Release/netstandard2.0/FSharp.Data.GraphQL.Client.dll"
17+
#r "../../src/FSharp.Data.GraphQL.Client/bin/Release/typeproviders/fsharp41/net461/netstandard.dll"
1818

1919
open FSharp.Data.GraphQL
2020

@@ -44,7 +44,7 @@ printfn "Things: %A\n" things
4444
// Although subscription operations can be created, the client provider still
4545
// does not work with web sockets - only the immediate response will be known.
4646
let operation =
47-
MyProvider.Operation<"""query q {
47+
MyProvider.Operation<"""query AE {
4848
hero (id: "1000") {
4949
name
5050
appearsIn

samples/client-provider/using_query_file.fsx

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,20 @@
1212
// #r "../../src/FSharp.Data.GraphQL.Client/bin/Debug/net461/FSharp.Data.GraphQL.Client.dll"
1313

1414
// Uncomment those to use dotnet build command for the client assembly using netstandard2.0
15-
#r "../../src/FSharp.Data.GraphQL.Client/bin/Debug/netstandard2.0/FSharp.Data.GraphQL.Shared.dll"
16-
#r "../../src/FSharp.Data.GraphQL.Client/bin/Debug/netstandard2.0/FSharp.Data.GraphQL.Client.dll"
17-
#r "../../src/FSharp.Data.GraphQL.Client/bin/Debug/typeproviders/fsharp41/net461/netstandard.dll"
15+
#r "../../src/FSharp.Data.GraphQL.Client/bin/Release/netstandard2.0/FSharp.Data.GraphQL.Shared.dll"
16+
#r "../../src/FSharp.Data.GraphQL.Client/bin/Release/netstandard2.0/FSharp.Data.GraphQL.Client.dll"
17+
#r "../../src/FSharp.Data.GraphQL.Client/bin/Release/typeproviders/fsharp41/net461/netstandard.dll"
1818

1919
open FSharp.Data.GraphQL
2020

21-
type MyProvider = GraphQLProvider<"http://localhost:8084">
21+
type MyProvider = GraphQLProvider<"http://localhost:5000">
2222

23-
// If you pass a query file, it will load the query from it.
24-
let operation = MyProvider.Operation<"operation.graphql">()
2523

26-
let result = operation.Run()
24+
// If you pass a query file, it will load the query from it.
25+
let operation = MyProvider.Operation<"query GetSelf { viewer { self { name { f:full } } } }", "Foo">()
26+
let context = MyProvider.GetContext(httpHeaders=[("Authorization", "Mock [email protected]")])
27+
let result = operation.Run(context)
2728

28-
printfn "Data: %A\n" result.Data
29+
printfn "Data: %A\n" result.Data.Value.Viewer.Self.Name.
2930
printfn "Errors: %A\n" result.Errors
3031
printfn "Custom data: %A\n" result.CustomData

src/FSharp.Data.GraphQL.Client.DesignTime/DesignTimeCache.fs

Lines changed: 130 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,38 +3,142 @@
33
44
namespace FSharp.Data.GraphQL
55

6-
open FSharp.Data.GraphQL.Client
6+
open System
77
open System.Collections.Concurrent
8+
open System.Collections.Generic
9+
open System.Timers
10+
open FSharp.Data.GraphQL.Client
811
open ProviderImplementation.ProvidedTypes
912

13+
// see: cache implementation http://www.fssnip.net/7UT/title/Threadsafe-Generic-MemoryCache-and-Memoize-Function
14+
15+
16+
type CacheExpirationPolicy =
17+
| NoExpiration
18+
| AbsoluteExpiration of TimeSpan
19+
| SlidingExpiration of TimeSpan
20+
21+
type CacheEntryExpiration =
22+
| NeverExpires
23+
| ExpiresAt of DateTime
24+
| ExpiresAfter of TimeSpan
25+
26+
type CacheEntry<'key, 'value> =
27+
{ Key: 'key
28+
Value: 'value
29+
Expiration: CacheEntryExpiration
30+
LastUsage: DateTime }
31+
32+
module CacheExpiration =
33+
let isExpired (entry: CacheEntry<_,_>) =
34+
match entry.Expiration with
35+
| NeverExpires -> false
36+
| ExpiresAt date -> DateTime.UtcNow > date
37+
| ExpiresAfter window -> (DateTime.UtcNow - entry.LastUsage) > window
38+
39+
type private IMemoryCacheStore<'key, 'value> =
40+
inherit IEnumerable<CacheEntry<'key, 'value>>
41+
abstract member Add: CacheEntry<'key, 'value> -> unit
42+
abstract member GetOrAdd: 'key -> ('key -> CacheEntry<'key, 'value>) -> CacheEntry<'key, 'value>
43+
abstract member Remove: 'key -> unit
44+
abstract member Contains: 'key -> bool
45+
abstract member Update: 'key -> (CacheEntry<'key, 'value> -> CacheEntry<'key, 'value>) -> unit
46+
abstract member TryFind: 'key -> CacheEntry<'key, 'value> option
47+
48+
type MemoryCache<'key, 'value> (?cacheExpirationPolicy) =
49+
let policy = defaultArg cacheExpirationPolicy NoExpiration
50+
let store =
51+
let entries = ConcurrentDictionary<'key, CacheEntry<'key, 'value>>()
52+
let get, getEnumerator =
53+
let values = entries |> Seq.map (fun kvp -> kvp.Value)
54+
(fun () -> values), (fun () -> values.GetEnumerator())
55+
{new IMemoryCacheStore<'key, 'value> with
56+
member __.Add entry = entries.AddOrUpdate(entry.Key, entry, fun _ _ -> entry) |> ignore
57+
member __.GetOrAdd key getValue = entries.GetOrAdd(key, getValue)
58+
member __.Remove key = entries.TryRemove key |> ignore
59+
member __.Contains key = entries.ContainsKey key
60+
member __.Update key update =
61+
match entries.TryGetValue(key) with
62+
| (true, entry) -> entries.AddOrUpdate(key, entry, fun _ entry -> update entry) |> ignore
63+
| _ -> ()
64+
member __.TryFind key =
65+
match entries.TryGetValue(key) with
66+
| (true, entry) -> Some entry
67+
| _ -> None
68+
member __.GetEnumerator () = getEnumerator ()
69+
member __.GetEnumerator () = getEnumerator () :> Collections.IEnumerator
70+
}
71+
72+
let checkExpiration () =
73+
store
74+
|> Seq.filter CacheExpiration.isExpired
75+
|> Seq.map (fun entry -> entry.Key)
76+
|> Seq.iter store.Remove
77+
78+
let newCacheEntry key value =
79+
{ Key = key
80+
Value = value
81+
Expiration = match policy with
82+
| NoExpiration -> NeverExpires
83+
| AbsoluteExpiration time -> ExpiresAt (DateTime.UtcNow + time)
84+
| SlidingExpiration window -> ExpiresAfter window
85+
LastUsage = DateTime.UtcNow
86+
}
87+
88+
let add key value =
89+
if key |> store.Contains
90+
then store.Update key (fun entry -> {entry with Value = value; LastUsage = DateTime.UtcNow})
91+
else store.Add <| newCacheEntry key value
92+
93+
let remove key =
94+
store.Remove key
95+
96+
let get key =
97+
store.TryFind key |> Option.bind (fun entry -> Some entry.Value)
98+
99+
let getOrAdd key value =
100+
store.GetOrAdd key (fun _ -> newCacheEntry key value)
101+
|> fun entry -> entry.Value
102+
103+
let getOrAddResult key f =
104+
store.GetOrAdd key (fun _ -> newCacheEntry key <| f())
105+
|> fun entry -> entry.Value
106+
107+
let getTimer (expiration: TimeSpan) =
108+
if expiration.TotalSeconds < 1.0
109+
then TimeSpan.FromMilliseconds 100.0
110+
elif expiration.TotalMinutes < 1.0
111+
then TimeSpan.FromSeconds 1.0
112+
else TimeSpan.FromMinutes 1.0
113+
|> fun interval -> new Timer(interval.TotalMilliseconds)
114+
115+
let timer =
116+
match policy with
117+
| NoExpiration -> None
118+
| AbsoluteExpiration time -> time |> getTimer |> Some
119+
| SlidingExpiration time -> time |> getTimer |> Some
120+
121+
let observer =
122+
match timer with
123+
| Some t ->
124+
let disposable = t.Elapsed |> Observable.subscribe (fun _ -> checkExpiration())
125+
t.Start()
126+
Some disposable
127+
| None -> None
128+
129+
member __.Add key value = add key value
130+
member __.Remove key = remove key
131+
member __.Get key = get key
132+
member __.GetOrAdd key value = getOrAdd key value
133+
member __.GetOrAddResult key f = getOrAddResult key f
134+
135+
10136
type internal ProviderKey =
11137
{ IntrospectionLocation : IntrospectionLocation
12138
CustomHttpHeadersLocation : StringLocation }
13139

14-
type internal CacheInvalidator (key : ProviderKey, invalidateFn : ProviderKey -> unit) =
15-
let lockObj = obj()
16-
let mutable remainingTime = 30000
17-
do
18-
async {
19-
while remainingTime > 0 do
20-
do! Async.Sleep(1000)
21-
lock lockObj (fun _ -> remainingTime <- remainingTime - 1000)
22-
invalidateFn key
23-
} |> Async.Start
24-
member __.Reset() = lock lockObj (fun _ -> remainingTime <- 30000)
25-
26140
module internal DesignTimeCache =
27-
let private cache = ConcurrentDictionary<ProviderKey, CacheInvalidator * ProvidedTypeDefinition>()
28-
141+
let private expiration = CacheExpirationPolicy.SlidingExpiration (TimeSpan.FromSeconds 30.0)
142+
let private cache = MemoryCache<ProviderKey, ProvidedTypeDefinition>(expiration)
29143
let getOrAdd (key : ProviderKey) (defMaker : unit -> ProvidedTypeDefinition) =
30-
if not (cache.ContainsKey(key))
31-
then
32-
let def = defMaker()
33-
let invalidateFn location = cache.TryRemove(location) |> ignore
34-
let invalidator = CacheInvalidator(key, invalidateFn)
35-
cache.TryAdd(key, (invalidator, def)) |> ignore
36-
def
37-
else
38-
let invalidator, def = cache.[key]
39-
invalidator.Reset()
40-
def
144+
cache.GetOrAddResult key defMaker

src/FSharp.Data.GraphQL.Client.DesignTime/FSharp.Data.GraphQL.Client.DesignTime.fsproj

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,14 @@
2828
<Compile Include="..\FSharp.Data.GraphQL.Client\GraphQLClient.fs" />
2929
<Compile Include="..\FSharp.Data.GraphQL.Client\GraphQLProviderRuntimeContext.fs" />
3030
<Compile Include="..\FSharp.Data.GraphQL.Client\Locations.fs" />
31-
<Compile Include="DesignTimeCache.fs" />
3231
<Compile Include="..\FSharp.Data.GraphQL.Client\BaseTypes.fs" />
33-
<Compile Include="ProvidedTypes.fs" />
32+
<Compile Include="DesignTimeCache.fs" />
33+
<Compile Include="ProvidedTypesHelper.fs" />
3434
<Compile Include="GraphQLProvider.DesignTime.fs" />
3535
<None Include="paket.references" />
3636
<None Include="..\..\packages\common\NETStandard.Library.NETFramework\build\net461\lib\netstandard.dll" Condition="'$(TargetFramework)' == 'net461'">
3737
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
3838
</None>
39-
</ItemGroup>
40-
<ItemGroup>
4139
<ProjectReference Include="..\FSharp.Data.GraphQL.Shared\FSharp.Data.GraphQL.Shared.fsproj" />
4240
</ItemGroup>
4341
<Import Project="..\..\.paket\Paket.Restore.targets" />

src/FSharp.Data.GraphQL.Client.DesignTime/GraphQLProvider.DesignTime.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ type GraphQLTypeProvider (config) as this =
1616

1717
let ns = "FSharp.Data.GraphQL"
1818
let asm = Assembly.GetExecutingAssembly()
19-
19+
2020
do this.AddNamespace(ns, [Provider.makeProvidedType(asm, ns, config.ResolutionFolder)])
2121

2222
[<assembly:TypeProviderAssembly>]

0 commit comments

Comments
 (0)