Return partial object in Vapor 3 - swift

I would like to return a partial object in a response for another object type.
For example, I have a UserProfile model:
var id: Int?
var email: String
var firstName: String?
var lastName: String?
and an Adult model:
var id: Int?
var nickname: String
var type: String
var user: User.UserProfile
var family: Family
Say I would like to return just the UserProfile's email address in the Adult response, what is the way to go about that?
I have tried an approach with child/parent relationships, where my Adult model is more like:
var id: Int?
var nickname: String
var type: String
var user: User.ID
var family: Family
..but then my response just contains an object ID, but I really want to return a partial (or even full in some cases) object.
Thanks in advance.

The way this is done is to create a 'public' definition of your model, which will represent the JSON you return from your route.
For your model, you might create a struct like this:
struct AdultResponse: Content {
var id: Int?
var nickname: String
var type: String
var email: String
var family: Family
init(adult: Adult) {
self.id = adult.id
self.nickname = adult.nickname
self.type = adult.type
self.email = adult.user.email
self.family = adult.family
}
}
You can then get your Adult model from the database, create an AdultResponse and return that from your route.

Related

Inheritance from non-protocol type 'PFObject'

I am getting this error Inheritance from non-protocol type 'PFObject' on Xcode with Swift while trying to create a Model, here is the code of the model:
import Foundation
import ParseSwift
import Parse
import SwiftUI
struct Category: ParseObject, PFObject {
// Required properties from ParseObject protocol
var originalData: Data?
var objectId: String?
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?
// Custom fields for the contact's information
var name: String = ""
var cover: String = ""
var color: String = ""
var createdBy: String = ""
}
extension Category {
init(name: String, cover: String, color: String, createdBy: String) {
self.name = name
self.cover = cover
self.color = color
self.createdBy = createdBy
}
}
What am I doing wrong?
It looks like you are trying to use Parse-Swift and the Parse Objective-C SDK at the same time which you shouldn't be doing. Your ParseObject is setup using Parse-Swift so assuming that's what you want to use, remove, import Parse and your Parse Object should look like:
import Foundation
import ParseSwift
import SwiftUI
struct Category: ParseObject {
// Required properties from ParseObject protocol
var originalData: Data?
var objectId: String?
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?
// All Custom fields should be optional
var name: String?
var cover: String?
var color: String?
var createdBy: String?
}
extension Category {
init(name: String, cover: String, color: String, createdBy: String) {
self.name = name
self.cover = cover
self.color = color
self.createdBy = createdBy
}
}
Remove the Parse dependency completely from your project as Parse-Swift doesn't use or need it at all. The playgrounds in Parse-Swift show how to use the SDK correctly along with any imports that are needed to use the SDK.

Environmentobject keep track of arrays variables

I'm pretty new to xCode so this could have an obvious answer.
I've just learned about environment objects and created the following one:
import SwiftUI
class Data: ObservableObject {
#Published var types = [Type]()
#Published var customers = [Customer]()
#Published var templates = [SubscriptionTemplate]()
#Published var subscriptions = [Subscription]()
#Published var giftCodes = [Giftcode]()
}
As you can see the object contains an array of objects. One of these is a customer array. The customer object looks like this:
import SwiftUI
class Customer: Identifiable, Codable{
var id: Int
var firstname: String
var lastname: String
var address: String
var plz: Int
var place: String
var credit: Int
init(id: Int, firstname: String, lastname: String, address: String, plz: Int, place: String, credit: Int) {
self.id = id
self.firstname = firstname
self.lastname = lastname
self.address = address
self.plz = plz
self.place = place
self.credit = credit
}
}
extension Customer: Equatable {
static func == (lhs: Customer, rhs: Customer) -> Bool {
return lhs.id == rhs.id
}
}
In my project, I implemented an API call to update the customer. This works like a charm, but after updating, I also want to fetch the customer objects with the following method:
API().fetchCustomers { (customers) in
self.data.customers = customers
}
After updating an object this doesn't work. The environment object doesn't update, but after creating a new object or fetching the data initial, it works.
What is the difference between the update and the create / fetch?
Make Customer a value type (ie. struct):
struct Customer: Identifiable, Codable{
var id: Int
// ... other code

Create an object array with few object properties of another object array using map

Suppose we have an Employee class like this
class Employee {
var id: String?
var name: String?
var role: String?
var age: Int?
var salary: Int?
}
var employeeList: [Employee]
I have to create a new object array with just few properties(eg: id, name, age) from employeeList.
Is there any other way(like map) other than using a for-loop to iterate the employeeList?
If you wanted to use map, you could do something like the following:
class Employee {
var id: String?
var name: String?
var role: String?
var age: Int?
var salary: Int?
}
var employeeList: [Employee]
var employeeModifiedList = employeeList.map {
(id: $0.id, name: $0.name, age: $0.age)
}
Something like this?
let myData: [(String?, String?, Int?)] = employeeList.map { ($0.id, $0.name, $0.age) }
Although not sure why your id is String type... usually ID's are Int

Copy one struct object

i have to quite similar struct objects. but one includes more values than the other. As the initial is required for KituraKuery methods i can not modify it but require more information for future processing.
my problem is now, that these struct objects look like this:
struct provider: Codable {
var firstName: String?
var lastName: String?
var email:String?
}
extension provider: Model{
class Persistence {}
}
struct provider2: Codable {
var firstName: String?
var lastName: String?
var email:String?
var providerCategories: [categories]?
}
extension provider: Model{
class Persistence {}
}
what i need is basically a smarter way to copy information from provider to provider2.
what i did as of now is i provided an init to provider2 taking provider as input and adding all values to it.
struct provider2: Codable {
var firstName: String?
var lastName: String?
var email:String?
var providerCategories: [categories]?
init(provider: provider?) {
if let provider = provider{
firstName = provider.firstName
lastName = provider.lastName
email = provider.lastName
}
}
extension provider: Model{
class Persistence {}
}
i however believe this is probably the worst way and there are much better and more lean approaches to it.
I tried myself on protocols but could that not really get to work.
Any input would be great :)
In your approach both Provider and Provider2 struct are tightly coupled to each other. So lets say in future if you want to change Provider struct or you want to initialise Provider2 struct with another struct, then you need to change lot of things.
We can solve the problem easily by decoupling both Provider and Provider2 struct
protocol BasicInfo {
var firstName: String? { get set }
var lastName: String? { get set }
var email:String? { get set }
}
protocol Address {
var address: String? {get set}
}
struct Provider: BasicInfo {
var firstName: String?
var lastName: String?
var email: String?
}
struct Provider2: BasicInfo, Address {
var firstName: String?
var lastName: String?
var email:String?
var address: String?
init(basic: BasicInfo, add: String) {
firstName = basic.firstName
lastName = basic.lastName
email = basic.email
address = add
}
}
//Below are instances of respective struct
let provider1 = Provider(firstName: "Test1", lastName: "TestLast1", email: "test1#gmail.com")
var provider2 = Provider2(basic: provider1, add: "Germany")
In above code i have two different Struct Provider and Provider2. Provider2 contains more variable than Provider (i have just added a single var to demonstrate). Now lets say in future we don't require Provider to fill Provider2, we have a new struct Provider3 which will fill Provider2 values.
struct Provider3: BasicInfo {
var firstName: String?
var lastName: String?
var email: String?
var middleName: String? //new property added
}
//Below are instances of respective struct
let provider3 = Provider3(firstName: "Test1", lastName: "TestLast1", email: "test1#gmail.com")
var provider2 = Provider2(basic: provider3, add: "Germany")
As you see there is no changes in struct Provider2, we have just introduce a new struct, create instance of new struct and passed that instance to Provider2 init method.
You could use extensions for this:
extension provider {
func asProvider2() -> provider2 {
return provider2(firstName: firstName,
lastName: lastName,
email: email,
providerCategories: nil)
}
}
// Then you can use it like this:
let bar = provider(firstName: "foo", lastName: "bar", email: "baz")
let bar2 = bar.asProvider2()

Simplify Swift data struct

Any suggestion on how to simplify this data struct? The data will be saved as a dictionary on the user's drive and when I read the data from the drive I have to convert them back to Member for easy accessing the properties.
I would like to have it typesafe.
struct Member {
var id: Int
var firstname: String
var lastname: String
var address: String?
var zipCode: Int?
var city: String?
enum Value: String {
case id = "id"
case firstname = "firstname"
case lastname = "lastname"
case address = "address"
case zipCode = "zipCode"
case city = "city"
}
var member: [String:Any] {
return [
Value.id.rawValue:Int(),
Value.firstname.rawValue:firstname,
Value.lastname.rawValue:lastname,
Value.address.rawValue:address ?? String(),
Value.zipCode.rawValue:zipCode ?? Int(),
Value.city.rawValue:city ?? String()
]
}
}
func memberToDic(member: Member) -> [String:Any] {
return [
Member.Value.firstname.rawValue:member.firstname,
Member.Value.lastname.rawValue:member.lastname,
Member.Value.address.rawValue:member.address ?? String(),
Member.Value.zipCode.rawValue:member.zipCode ?? Int(),
Member.Value.city.rawValue:member.city ?? String()
]
}
func dicToMember(dic: [String:Any]) -> Member {
return Member(
id: dic[Member.Value.id.rawValue] as! Int,
firstname: dic[Member.Value.firstname.rawValue] as! String,
lastname: dic[Member.Value.lastname.rawValue] as! String,
address: dic[Member.Value.address.rawValue] as? String,
zipCode: dic[Member.Value.zipCode.rawValue] as? Int,
city: dic[Member.Value.city.rawValue] as? String
)
}
Almost certainly, this is the correct implementation:
struct Member: Codable {
var id: Int
var firstName: String // "first name" is two words, so capitalize "name"
var lastName: String
var address: String // "No address" should be empty, not nil
var zipCode: String // ZIP codes are not integers
var city: String // "No city" should be empty, not nil
}
In order to save this as a plist, use PropertyListEncoder:
let data = try PropertyListEncoder().encode(member)
To read it, use PropertyListDecoder.
Codable automatically creates key mappings for your properties, so there's no need for Value.
You should strongly avoid creating or consuming [String: Any] dictionaries. These exist mostly due to Objective-C interfaces that could not generate strong types.
If address, zipCode, and city all should be set together, or not set together, then you should collect them into a single struct:
struct Address: Codable {
var streetAddress: String
var zipCode: String
var city: String
}
struct Member: Codable {
var id: Int
var firstName: String // "first name" is two words, so capitalize "name"
var lastName: String
var address: Address?
}
In this case, and Optional makes sense because "empty" is not the same thing as "missing."