Skip to content

Commit 9944d84

Browse files
authored
Merge pull request #26 from vapor-community/feature/datastore
Feature/datastore
2 parents e665242 + a84e7af commit 9944d84

File tree

4 files changed

+186
-3
lines changed

4 files changed

+186
-3
lines changed

Package.swift

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,13 @@ let package = Package(
1414
.library(
1515
name: "CloudStorage",
1616
targets: ["CloudStorage"]),
17+
.library(
18+
name: "CloudDatastore",
19+
targets: ["CloudDatastore"]),
1720
],
1821
dependencies: [
19-
.package(url: "https://github.com/vapor/vapor.git", from: "4.0.0-rc"),
20-
.package(url: "https://github.com/vapor-community/google-cloud-kit.git", from: "1.0.0-alpha.11")
22+
.package(url: "https://github.com/vapor/vapor.git", from: "4.0.0"),
23+
.package(url: "https://github.com/vapor-community/google-cloud-kit.git", from: "1.0.0-rc")
2124
],
2225
targets: [
2326
.target(
@@ -34,5 +37,12 @@ let package = Package(
3437
.product(name: "GoogleCloudStorage", package: "google-cloud-kit"),
3538
.target(name: "GoogleCloud")
3639
]),
40+
.target(
41+
name: "CloudDatastore",
42+
dependencies: [
43+
.product(name: "Vapor", package: "vapor"),
44+
.product(name: "GoogleCloudDatastore", package: "google-cloud-kit"),
45+
.target(name: "GoogleCloud")
46+
]),
3747
]
3848
)

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,15 @@
1111
In your `Package.swift` file, add the following
1212

1313
```swift
14-
.package(url: "https://github.com/vapor-community/google-cloud.git", from: "1.0.0-rc")
14+
.package(url: "https://github.com/vapor-community/google-cloud.git", from: "1.0.0")
1515
```
1616

1717
## Usage
1818
You can check each supported API's README for a getting started guide.
1919

2020
### Supported APIs
2121
[x] [CloudStorage](/Sources/CloudStorage/README.md)
22+
[x] [CloudDatastore](/Sources/CloudDatastore/README.md)
2223

2324
### A More detailed guide can be found [here](https://github.com/vapor-community/google-cloud-kit).
2425

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
//
2+
// GoogleCloudDatastoreAPI.swift
3+
//
4+
//
5+
// Created by Andrew Edwards on 04/10/20.
6+
//
7+
8+
import Vapor
9+
@_exported import Datastore
10+
@_exported import GoogleCloud
11+
12+
extension Application.GoogleCloudPlatform {
13+
private struct CloudDatastoreAPIKey: StorageKey {
14+
typealias Value = GoogleCloudDatastoreAPI
15+
}
16+
17+
private struct CloudDatastoreConfigurationKey: StorageKey {
18+
typealias Value = GoogleCloudDatastoreConfiguration
19+
}
20+
21+
private struct CloudDatastoreHTTPClientKey: StorageKey, LockKey {
22+
typealias Value = HTTPClient
23+
}
24+
25+
public var datastore: GoogleCloudDatastoreAPI {
26+
get {
27+
if let existing = self.application.storage[CloudDatastoreAPIKey.self] {
28+
return existing
29+
} else {
30+
return .init(application: self.application, eventLoop: self.application.eventLoopGroup.next())
31+
}
32+
}
33+
34+
nonmutating set {
35+
self.application.storage[CloudDatastoreAPIKey.self] = newValue
36+
}
37+
}
38+
39+
public struct GoogleCloudDatastoreAPI {
40+
public let application: Application
41+
public let eventLoop: EventLoop
42+
43+
/// A client used to interact with the `GoogleCloudDatastore` API.
44+
public var client: GoogleCloudDatastoreClient {
45+
do {
46+
let new = try GoogleCloudDatastoreClient(credentials: self.application.googleCloud.credentials,
47+
config: self.configuration,
48+
httpClient: self.http,
49+
eventLoop: self.eventLoop)
50+
return new
51+
} catch {
52+
fatalError("\(error.localizedDescription)")
53+
}
54+
}
55+
56+
/// The configuration for using `GoogleCloudDatastore` APIs.
57+
public var configuration: GoogleCloudDatastoreConfiguration {
58+
get {
59+
if let configuration = application.storage[CloudDatastoreConfigurationKey.self] {
60+
return configuration
61+
} else {
62+
fatalError("Cloud datastore configuration has not been set. Use app.googleCloud.datastore.configuration = ...")
63+
}
64+
}
65+
set {
66+
if application.storage[CloudDatastoreConfigurationKey.self] == nil {
67+
application.storage[CloudDatastoreConfigurationKey.self] = newValue
68+
} else {
69+
fatalError("Attempting to override credentials configuration after being set is not allowed.")
70+
}
71+
}
72+
}
73+
74+
/// Custom `HTTPClient` that ignores unclean SSL shutdown.
75+
public var http: HTTPClient {
76+
if let existing = application.storage[CloudDatastoreHTTPClientKey.self] {
77+
return existing
78+
} else {
79+
let lock = application.locks.lock(for: CloudDatastoreHTTPClientKey.self)
80+
lock.lock()
81+
defer { lock.unlock() }
82+
if let existing = application.storage[CloudDatastoreHTTPClientKey.self] {
83+
return existing
84+
}
85+
let new = HTTPClient(
86+
eventLoopGroupProvider: .shared(application.eventLoopGroup),
87+
configuration: HTTPClient.Configuration(ignoreUncleanSSLShutdown: true)
88+
)
89+
application.storage.set(CloudDatastoreHTTPClientKey.self, to: new) {
90+
try $0.syncShutdown()
91+
}
92+
return new
93+
}
94+
}
95+
}
96+
}
97+
98+
extension Request {
99+
private struct GoogleCloudDatastoreKey: StorageKey {
100+
typealias Value = GoogleCloudDatastoreClient
101+
}
102+
103+
/// A client used to interact with the `GoogleCloudDatastore` API
104+
public var gcDatastore: GoogleCloudDatastoreClient {
105+
if let existing = application.storage[GoogleCloudDatastoreKey.self] {
106+
return existing.hopped(to: self.eventLoop)
107+
} else {
108+
let new = Application.GoogleCloudPlatform.GoogleCloudDatastoreAPI(application: self.application, eventLoop: self.eventLoop).client
109+
application.storage[GoogleCloudDatastoreKey.self] = new
110+
return new
111+
}
112+
}
113+
}
114+

Sources/CloudDatastore/README.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# GoogleCloudDatastoreAPI
2+
3+
## Getting Started
4+
If you only need to use the [Google Cloud Datastore API](https://cloud.google.com/datastore/), then this guide will help you get started.
5+
6+
In your `Package.swift` file, make sure you have the following dependencies and targets
7+
8+
```swift
9+
dependencies: [
10+
//...
11+
.package(url: "https://github.com/vapor-community/google-cloud.git", from: "1.0.0-rc"),
12+
],
13+
targets: [
14+
.target(name: "MyAppName", dependencies: [
15+
//...
16+
.product(name: "CloudDatastore", package: "google-cloud"),
17+
]),
18+
]
19+
```
20+
21+
Now you can setup the configuration for any GCP API globally via `Application`.
22+
23+
In `configure.swift`
24+
25+
```swift
26+
import CloudDatastore
27+
28+
app.googleCloud.credentials = try GoogleCloudCredentialsConfiguration(projectId: "myprojectid-12345",
29+
credentialsFile: "~/path/to/service-account.json")
30+
```
31+
Next we setup the CloudDatastore API configuration (specific to this API).
32+
33+
```swift
34+
app.googleCloud.datastore.configuration = .default()
35+
```
36+
37+
Now we can start using the GoogleCloudDatastore API
38+
There's a handy extension on `Request` that you can use to get access to a cloud datastore client via a property named `gcDatastore`.
39+
40+
```swift
41+
42+
struct LookupRequest: Content {
43+
var name: String
44+
}
45+
46+
func lookupEntities(_ req: Request) throws {
47+
let name = try req.content.decode(LookupRequest.self)
48+
49+
let pathElement = PathElement(.name(name.name), kind: "MyEntity")
50+
let partitionId = PartitionId(projectId: "my-project")
51+
let key = Key(partitionId: partitionId, path: [pathElement])
52+
53+
req.gcDatastore.project.lookup(keys: [key]).map { response in
54+
print(response.found.count) // prints 1 if entity exists
55+
}
56+
}
57+
```
58+

0 commit comments

Comments
 (0)