main.swift 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  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 Foundation
  17. import gRPC
  18. import OAuth2
  19. import Commander
  20. // Convert Encodable objects to dictionaries of property-value pairs.
  21. class PropertiesEncoder {
  22. static func encode<T : Encodable>(_ value : T) throws -> [String:Any]? {
  23. let plist = try PropertyListEncoder().encode(value)
  24. let properties = try PropertyListSerialization.propertyList(from:plist, options:[], format:nil)
  25. return properties as? [String:Any]
  26. }
  27. }
  28. // Create Decodable objects from dictionaries of property-value pairs.
  29. class PropertiesDecoder {
  30. static func decode<T: Decodable>(_ type: T.Type, from: [String:Any]) throws -> T {
  31. let plist = try PropertyListSerialization.data(fromPropertyList: from, format: .binary, options:0)
  32. return try PropertyListDecoder().decode(type, from: plist)
  33. }
  34. }
  35. // a Swift interface to the Google Cloud Datastore API
  36. class Datastore {
  37. var projectID : String
  38. var service : Google_Datastore_V1_DatastoreService!
  39. let scopes = ["https://www.googleapis.com/auth/datastore"]
  40. init(projectID:String) {
  41. self.projectID = projectID
  42. }
  43. func authenticate() throws {
  44. var authToken : String!
  45. if let provider = DefaultTokenProvider(scopes:scopes) {
  46. let sem = DispatchSemaphore(value: 0)
  47. try provider.withToken() {(token, error) -> Void in
  48. if let token = token {
  49. authToken = token.AccessToken
  50. }
  51. sem.signal()
  52. }
  53. sem.wait()
  54. }
  55. if authToken == nil {
  56. print("ERROR: No OAuth token is available. Did you set GOOGLE_APPLICATION_CREDENTIALS?")
  57. exit(-1)
  58. }
  59. // Initialize gRPC service
  60. gRPC.initialize()
  61. service = Google_Datastore_V1_DatastoreService(address:"datastore.googleapis.com")
  62. service.metadata = Metadata(["authorization":"Bearer " + authToken])
  63. }
  64. func performList<T: Codable>(type: T.Type) throws -> [Int64 : T]{
  65. var request = Google_Datastore_V1_RunQueryRequest()
  66. request.projectID = projectID
  67. var query = Google_Datastore_V1_GqlQuery()
  68. query.queryString = "select * from " + String(describing: type)
  69. request.gqlQuery = query
  70. let result = try service.runquery(request)
  71. var entities : [Int64 : T] = [:]
  72. for entityResult in result.batch.entityResults {
  73. var properties : [String:Any] = [:]
  74. for property in entityResult.entity.properties {
  75. let key = property.key
  76. switch property.value.valueType! {
  77. case .integerValue(let v):
  78. properties[key] = v
  79. case .stringValue(let v):
  80. properties[key] = v
  81. default:
  82. print("?")
  83. }
  84. }
  85. let entity = try PropertiesDecoder.decode(type, from:properties)
  86. entities[entityResult.entity.key.path[0].id] = entity
  87. }
  88. return entities
  89. }
  90. func performInsert<T: Codable>(thing: T) throws {
  91. var request = Google_Datastore_V1_CommitRequest()
  92. request.projectID = projectID
  93. request.mode = .nonTransactional
  94. var pathElement = Google_Datastore_V1_Key.PathElement()
  95. pathElement.kind = String(describing: type(of: thing))
  96. var key = Google_Datastore_V1_Key()
  97. key.path = [pathElement]
  98. var entity = Google_Datastore_V1_Entity()
  99. entity.key = key
  100. let properties = try PropertiesEncoder.encode(thing)!
  101. for (k,v) in properties {
  102. var value = Google_Datastore_V1_Value()
  103. switch v {
  104. case let v as String:
  105. value.stringValue = v
  106. case let v as Int:
  107. value.integerValue = Int64(v)
  108. default:
  109. break
  110. }
  111. entity.properties[k] = value
  112. }
  113. var mutation = Google_Datastore_V1_Mutation()
  114. mutation.insert = entity
  115. request.mutations.append(mutation)
  116. let result = try service.commit(request)
  117. for mutationResult in result.mutationResults {
  118. print("\(mutationResult)")
  119. }
  120. }
  121. func performDelete(kind: String,
  122. id: Int64) throws {
  123. var request = Google_Datastore_V1_CommitRequest()
  124. request.projectID = projectID
  125. request.mode = .nonTransactional
  126. var pathElement = Google_Datastore_V1_Key.PathElement()
  127. pathElement.kind = kind
  128. pathElement.id = id
  129. var key = Google_Datastore_V1_Key()
  130. key.path = [pathElement]
  131. var mutation = Google_Datastore_V1_Mutation()
  132. mutation.delete = key
  133. request.mutations.append(mutation)
  134. let result = try service.commit(request)
  135. for mutationResult in result.mutationResults {
  136. print("\(mutationResult)")
  137. }
  138. }
  139. }
  140. let projectID = "your-project-identifier"
  141. struct Thing : Codable {
  142. var name: String
  143. var number: Int
  144. }
  145. Group {
  146. $0.command("insert") { (number:Int) in
  147. let datastore = Datastore(projectID: projectID)
  148. try datastore.authenticate()
  149. let thing = Thing(name:"Thing", number:number)
  150. try datastore.performInsert(thing:thing)
  151. }
  152. $0.command("delete") { (id:Int) in
  153. let datastore = Datastore(projectID: projectID)
  154. try datastore.authenticate()
  155. try datastore.performDelete(kind:"Thing", id:Int64(id))
  156. }
  157. $0.command("list") {
  158. let datastore = Datastore(projectID: projectID)
  159. try datastore.authenticate()
  160. let entities = try datastore.performList(type: Thing.self)
  161. print("\(entities)")
  162. }
  163. }.run()