main.swift 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /*
  2. * Copyright 2017, gRPC Authors All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. import Commander
  17. import Dispatch
  18. import Foundation
  19. import SwiftGRPC
  20. import OAuth2
  21. // Convert Encodable objects to dictionaries of property-value pairs.
  22. class PropertiesEncoder {
  23. static func encode<T: Encodable>(_ value: T) throws -> [String: Any]? {
  24. #if os(OSX)
  25. let plist = try PropertyListEncoder().encode(value)
  26. let properties = try PropertyListSerialization.propertyList(from: plist, options: [], format: nil)
  27. #else
  28. let data = try JSONEncoder().encode(value)
  29. let properties = try JSONSerialization.jsonObject(with: data, options: [])
  30. #endif
  31. return properties as? [String: Any]
  32. }
  33. }
  34. // Create Decodable objects from dictionaries of property-value pairs.
  35. class PropertiesDecoder {
  36. static func decode<T: Decodable>(_ type: T.Type, from: [String: Any]) throws -> T {
  37. #if os(OSX)
  38. let plist = try PropertyListSerialization.data(fromPropertyList: from, format: .binary, options: 0)
  39. return try PropertyListDecoder().decode(type, from: plist)
  40. #else
  41. let data = try JSONSerialization.data(withJSONObject: from, options: [])
  42. return try JSONDecoder().decode(type, from: data)
  43. #endif
  44. }
  45. }
  46. // a Swift interface to the Google Cloud Datastore API
  47. class Datastore {
  48. var projectID: String
  49. var service: Google_Datastore_V1_DatastoreServiceClient!
  50. let scopes = ["https://www.googleapis.com/auth/datastore"]
  51. init(projectID: String) {
  52. self.projectID = projectID
  53. }
  54. func authenticate() throws {
  55. var authToken: String!
  56. if let provider = DefaultTokenProvider(scopes: scopes) {
  57. let sem = DispatchSemaphore(value: 0)
  58. try provider.withToken { (token, _) -> Void in
  59. if let token = token {
  60. authToken = token.AccessToken
  61. }
  62. sem.signal()
  63. }
  64. sem.wait()
  65. }
  66. if authToken == nil {
  67. print("ERROR: No OAuth token is available. Did you set GOOGLE_APPLICATION_CREDENTIALS?")
  68. exit(-1)
  69. }
  70. // Initialize gRPC service
  71. gRPC.initialize()
  72. service = Google_Datastore_V1_DatastoreServiceClient(address: "datastore.googleapis.com")
  73. service.metadata = Metadata(["authorization": "Bearer " + authToken])
  74. }
  75. func performList<T: Codable>(type: T.Type) throws -> [Int64: T] {
  76. var request = Google_Datastore_V1_RunQueryRequest()
  77. request.projectID = projectID
  78. var query = Google_Datastore_V1_GqlQuery()
  79. query.queryString = "select * from " + String(describing: type)
  80. request.gqlQuery = query
  81. let result = try service.runquery(request)
  82. var entities: [Int64: T] = [:]
  83. for entityResult in result.batch.entityResults {
  84. var properties: [String: Any] = [:]
  85. for property in entityResult.entity.properties {
  86. let key = property.key
  87. switch property.value.valueType! {
  88. case .integerValue(let v):
  89. properties[key] = v
  90. case .stringValue(let v):
  91. properties[key] = v
  92. default:
  93. print("?")
  94. }
  95. }
  96. let entity = try PropertiesDecoder.decode(type, from: properties)
  97. entities[entityResult.entity.key.path[0].id] = entity
  98. }
  99. return entities
  100. }
  101. func performInsert<T: Codable>(thing: T) throws {
  102. var request = Google_Datastore_V1_CommitRequest()
  103. request.projectID = projectID
  104. request.mode = .nonTransactional
  105. var pathElement = Google_Datastore_V1_Key.PathElement()
  106. pathElement.kind = String(describing: type(of: thing))
  107. var key = Google_Datastore_V1_Key()
  108. key.path = [pathElement]
  109. var entity = Google_Datastore_V1_Entity()
  110. entity.key = key
  111. let properties = try PropertiesEncoder.encode(thing)!
  112. for (k, v) in properties {
  113. var value = Google_Datastore_V1_Value()
  114. switch v {
  115. case let v as String:
  116. value.stringValue = v
  117. case let v as Int:
  118. value.integerValue = Int64(v)
  119. default:
  120. break
  121. }
  122. entity.properties[k] = value
  123. }
  124. var mutation = Google_Datastore_V1_Mutation()
  125. mutation.insert = entity
  126. request.mutations.append(mutation)
  127. let result = try service.commit(request)
  128. for mutationResult in result.mutationResults {
  129. print("\(mutationResult)")
  130. }
  131. }
  132. func performDelete(kind: String,
  133. id: Int64) throws {
  134. var request = Google_Datastore_V1_CommitRequest()
  135. request.projectID = projectID
  136. request.mode = .nonTransactional
  137. var pathElement = Google_Datastore_V1_Key.PathElement()
  138. pathElement.kind = kind
  139. pathElement.id = id
  140. var key = Google_Datastore_V1_Key()
  141. key.path = [pathElement]
  142. var mutation = Google_Datastore_V1_Mutation()
  143. mutation.delete = key
  144. request.mutations.append(mutation)
  145. let result = try service.commit(request)
  146. for mutationResult in result.mutationResults {
  147. print("\(mutationResult)")
  148. }
  149. }
  150. }
  151. let projectID = "your-project-identifier"
  152. struct Thing: Codable {
  153. var name: String
  154. var number: Int
  155. }
  156. Group {
  157. $0.command("insert") { (number: Int) in
  158. let datastore = Datastore(projectID: projectID)
  159. try datastore.authenticate()
  160. let thing = Thing(name: "Thing", number: number)
  161. try datastore.performInsert(thing: thing)
  162. }
  163. $0.command("delete") { (id: Int) in
  164. let datastore = Datastore(projectID: projectID)
  165. try datastore.authenticate()
  166. try datastore.performDelete(kind: "Thing", id: Int64(id))
  167. }
  168. $0.command("list") {
  169. let datastore = Datastore(projectID: projectID)
  170. try datastore.authenticate()
  171. let entities = try datastore.performList(type: Thing.self)
  172. print("\(entities)")
  173. }
  174. }.run()