PivotProtocol in vapor - vapor

How to make a Pivot with the same objects?
I have this tried but get an mySQL error:
final class UserParent: Model, PivotProtocol {
var storage = Storage()
typealias Left = User
typealias Right = User
static var leftIdKey: String = "user_id_parent"
static var rightIdKey: String = "user_id_child"
init(row: Row) throws { }
func makeRow() throws -> Row {
let row = Row()
return row
}
}
//MARK: - Preparation
extension UserParent: Preparation {
static func prepare(_ database: Database) throws {
try database.create(self, closure: { builder in
builder.id()
builder.int("user_id_parent")
builder.int("user_id_child")
})
}
static func revert(_ database: Database) throws {
try database.delete(self)
}
}
and then i have this on my user object
var users: Siblings<User, User, UserParent> {
return siblings()
}
but I get this mySQL error
[MySQL Error: Unknown column 'user_parents.user_id' in 'where clause']

To complete tanner0101's answer:
Your model is correct, but your Siblings implementation must specify the custom keys as well.
var parentUsers: Siblings<User, User, UserParent> {
return siblings(localIdKey: "user_id_child", foreignIdKey: "user_id_parent")
}
var childUsers: Siblings<User, User, UserParent> {
return siblings(localIdKey: "user_id_parent", foreignIdKey: "user_id_child")
}

Related

Realm Swift duplicates item with primary key -> Threading problem?

I'm using ReamSwift to store data in my iOS application and I have troubles to figure out, why sometimes objects are duplicated in my application.
I use an UUID as primary key on every object. This property is defined in a base class and all the others are subclasses of that.
I use the update approach with a dictionary. So new objects are created and existing should be updated.
I use a central class which holds the Realm object and handles the update. This method could be called from multiple different threads.
This is my base class
import RealmSwift
open class RealmObject : Object {
static let ID_ATTRIBUTE : String = "id"
#objc dynamic var id : String = ""
override public static func primaryKey() -> String? {
return "id"
}
}
Central class managing swift.
This class holds the Realm Object
public var realm: Realm {
var tempRealm: Realm?
do {
tempRealm = try Realm(configuration: configuration)
}
catch let err {
print("------ERROR----- initializing realm\n \(err)")
}
if let tempRealm = tempRealm{
return tempRealm
}
return self.realm
}
This is the update method in the class. As a fallback if the id property is not set, it will be set as it is the primary key
func update<T: RealmObject>(_ obj : T, values : [String:Any?] ) -> T? {
var vals = values
do {
var res : T?
try realm.write {
if let idattr = vals[T.ID_ATTRIBUTE] as? String {
if(idattr.isEmpty) {
vals[T.ID_ATTRIBUTE] = UUID().uuidString
}
} else {
vals[T.ID_ATTRIBUTE] = UUID().uuidString
}
res = realm.create(T.self, value: vals, update: .modified)
}
return res
} catch {
return nil
}
}
Could calling the update method cause in any case the duplication as I set the primary key of the object? The problem is, I cannot reproduce to find the problem, i just encounter the issue from time to time and in the field from users.
One interesting thing, when a copy is deleted, also the other object will be deleted.
This is the method which deletes objects by id and type
func delete<T: RealmObject>(_ id : String, _ type : T.Type) -> Bool {
do {
let obj = get(id, T.self)
if let obj = obj {
try realm.write {
realm.delete(obj)
}
return true
} else {
return false
}
} catch {
return false
}
}

Swift 3 - Sequence ambiguous without more context

I tried to create a custom iterator which returns wrapper abcContainer over raw data class abc
// raw data class
class abc {
var name : String = "";
init( _ value : String) {
name = value;
}
}
// with container, only "name" is to be visible
class abcContainer {
private var _abc : abc;
init( _ obj : abc) {
_abc = obj;
}
// + extra methods here
func getName() -> String {
return _abc.name
}
}
The point would be that the dictionary would return instances of abcContainer instead of just the plain raw abc class.
I wanted to use the sequence protocol to make the conversion automatic, but I was not able to transform the [String:abc] into [String:abcContainer] automatically like this:
// the iterator is implemented just iterating the inner basic dict
// but wrapping the result value as abcContainer
class abcIterator : Sequence, IteratorProtocol {
private var __source : [String:abc]?;
var index = 0
var myIterator : DictionaryIterator<String, abc>;
init(_ ctxArray: [String:abc]) {
self.__source = ctxArray
index = 0;
myIterator = (__source?.makeIterator())!
}
func next() -> abcContainer? {
let nextItem = myIterator.next();
if(nextItem != nil) {
return abcContainer((nextItem?.value)!);
}
return nil;
}
}
// this was supposed to be the wrapper over the collection
class abcCollection : Sequence {
private var __source : [String:abc]?;
init(_ list: [String:abc]) {
self.__source = list
}
func makeIterator() -> abcIterator {
return abcIterator(self.__source!);
}
}
I'm probably missing something very basic here. When I try to use the collection like this:
var dict : [String:abc] = [String:abc]();
dict["abba"] = abc("John Smith");
for (key,value) in abcCollection(dict) {
print(key, value.getName());
}
I get error: Expression type "abcCollection" is ambiguous without more context
Does anyone have idea how to make it work? What is missing? I have a feeling that this answer has the information I need...
Swift 2 to 3 Migration for Swift Sequence Protocol
The problem in your original code is that abcCollection(dict)
returned a sequence of abcContainer objects, and those cannot
be assigned to a (key, value) tuple.
You can achieve your goal with
class abcCollection : Sequence {
private var __source : [String:abc]
init(_ list: [String:abc]) {
self.__source = list
}
public func makeIterator() -> AnyIterator<(AnyObject,abcContainer)> {
let mapped = self.__source.lazy.map {
($0.key as AnyObject, abcContainer($0.value))
}
return AnyIterator(mapped.makeIterator())
}
}
Making __source non-optional makes all the (optional) unwrappings
redundant, and lazy.map { ... } returns a lazily evaluated
sequence of key/value pairs which is then type-erased.
Ok, perhaps the answer was abcIterator was not necessary, you could have defined the iterator directly just like done in the linked answer like this:
class abcCollection : Sequence {
private var __source : [String:abc]?;
init(_ list: [String:abc]) {
self.__source = list
}
public func makeIterator() -> AnyIterator<(AnyObject,abcContainer)> {
var it = self.__source?.makeIterator();
return AnyIterator {
let n = it?.next();
if n == nil { return nil }
return (n?.key as AnyObject, abcContainer((n?.value)!))
}
}
}
After that, the custom collection returned wrapped objects correctly.

Query Realm get object which have particularly object in a list

I think this is a simple solution, but i´m stuck with the best approach.
My Realm Database is made with the objects POI and CATEGORY. Where a POI can have one or multiple object of CATEGORY
class POI: Object {
dynamic var id:String = ""
dynamic var name:String = ""
dynamic var visited:Bool = false;
let categories = List<CATEGORY>()
override static func primaryKey() -> String?
{
return "id";
}
}
Later I need to show the number of POI that have a particular CATEGORY, and the number of POI that have a given CATEGORY with the boolean visited has true.
Something like this:
func getAllVisitedPointsWithCategory(idCategory:String) -> Results<POI> {
}
func getAllPointsWithCategory(idCategory:String) -> Results<POI>{
}
Any suggestion?
This should work:
func getAllVisitedPointsWithCategory(idCategory:String) -> [POI] {
let containingPOI = getAllPointsWithCategory(idCategory)
return containingPOI.filter({ (poi) -> Bool in
return poi.visited
})
}
func getAllPointsWithCategory(idCategory:String) -> [POI] {
let realm = try! Realm()
let containingPOI = realm.objects(POI).filter({ (poi) -> Bool in
return poi.categories.contains({ (cat) -> Bool in
return idCategory == cat.id
})
})
return containingPOI
}
It's basically just querying data and filtering the result.
This can be done more concisely and faster by using Realm's query engine rather than filtering the objects individually in Swift:
func getAllVisitedPointsWithCategory(idCategory:String) -> Results<POI> {
return getAllPointsWithCategory(idCategory).filter("visited = true")
}
func getAllPointsWithCategory(idCategory:String) -> Results<POI>{
let realm = try! Realm()
return realm.objects(POI.self).filter("ANY categories.id = %#", idCategory)
}

func == from equatable protocol does not work for custom object, swift

My goal is to show a user list of history logins ( such as username ) if there are any. In order to do that, I am doing
1. Create an custom object named User like below
class User: NSObject
{
var login: String
init(login: String)
{
self.login = login
}
required init(coder aDecoder: NSCoder) {
login = aDecoder.decodeObjectForKey("login") as! String
}
func encodeWithCoder(aCoder: NSCoder) {
aCoder.encodeObject(login, forKey: "login")
}
}
// This conform to make sure that I compare the `login` of 2 Users
func ==(lhs: User, rhs: User) -> Bool
{
return lhs.login == rhs.login
}
At UserManager, Im doing save and retrieve an User. Before saving, I'm doing a check if the the list of history logins contains a User, I wont add it in, otherwise.
class UserManager : NSObject
{
static let sharedInstance = UserManager()
var userDefaults = NSUserDefaults.standardUserDefaults()
func saveUser(user:User)
{
var users = retrieveAllUsers()
// Check before adding
if !(users.contains(user))
{
users.append(user)
}
let encodedData = NSKeyedArchiver.archivedDataWithRootObject(users)
userDefaults.setObject(encodedData, forKey: "users")
userDefaults.synchronize()
}
func retrieveAllUsers() -> [User]
{
guard let data = userDefaults.objectForKey("users") as? NSData else
{
return [User]()
}
let users = NSKeyedUnarchiver.unarchiveObjectWithData(data) as! [User]
// Testing purpose
for user in users
{
print(user.login)
}
return users
}
}
At first time trying, I do
UserManager.sharedInstance.saveUser(User(login: "1234"))
Now it saves the first login. At second time, I also do
UserManager.sharedInstance.saveUser(User(login: "1234"))
UserManager still adds the second login into nsuserdefault. That means the function contains fails and it leads to
func ==(lhs: User, rhs: User) -> Bool
{
return lhs.login == rhs.login
}
does not work properly.
Does anyone know why or have any ideas about this.
The problem is that User derives from NSObject. This means that (as you rightly say) your == implementation is never being consulted. Swift's behavior is different for objects that derive from NSObject; it does things the Objective-C way. To implement equatability on an object that derives from NSObject, override isEqual:. That is what makes an NSObject-derived object equatable in a custom way, in both Objective-C and Swift.
Just paste this code right into your User class declaration, and contains will start working as you wish:
override func isEqual(object: AnyObject?) -> Bool {
if let other = object as? User {
if other.login == self.login {
return true
}
}
return false
}
What's going on?
As #matt already said, the problem is about equality.
Look
var users = [User]()
users.append(User(login: "1234"))
users.contains(User(login: "1234")) // false
Look again
var users = [User]()
let user = User(login: "1234")
users.append(user)
users.contains(user) // true <---- THIS HAS CHANGED
contains
The contains function is NOT using the logic you defined here
func ==(lhs: User, rhs: User) -> Bool {
return lhs.login == rhs.login
}
Infact it is simply comparing the memory addresses of the objects.
Solution
You can solve the issue passing your own logic to contains, just replace this
if !(users.contains(user)) {
users.append(user)
}
with this
if !(users.contains { $0.login == user.login }) {
users.append(user)
}

How to call static method provided by protocol in Swift

How to access to static protocol method within a instance
I have a list of Contact, the contact can be a FamilyContact that inherit from Contact and the GroupStatus protocol
I want to call the static method from GroupStatus but in vain...
Here is my code
protocol GroupStatus {
static func isPrivate() -> Bool // static method that indicates the status
}
protocol IsBusy {
func wizzIt()
}
class AdresseBook {
private var contacts = [Contact]()
func addOne(c: Contact) {
contacts.append(c)
}
func listNonPrivated() -> [Contact]? {
var nonPrivateContact = [Contact]()
for contact in contacts {
// here is I should call the static method provided by the protocol
if self is GroupStatus {
let isPrivate = contact.dynamicType.isPrivate()
if !isPrivate {
nonPrivateContact.append(contact)
}
}
nonPrivateContact.append(contact)
}
return nonPrivateContact
}
}
class Contact : Printable {
var name: String
init(name: String) {
self.name = name
}
func wizz() -> Bool {
if let obj = self as? IsBusy {
obj.wizzIt()
return true
}
return false
}
var description: String {
return self.name
}
}
class FamilyContact: Contact, GroupStatus {
static func isPrivate() -> Bool {
return true
}
}
I can't compile Contact.Type does not have a member named 'isPrivate'
How can I call it ? It works if I delete the static keyword, but I think is more logical to define it static.
If I replace
let isPrivate = contact.dynamicType.isPrivate()
by
let isPrivate = FamilyContact.isPrivate()
It works, but I can have more than 1 subclasses
If I remove the static keywork I can do it by this way :
if let c = contact as? GroupStatus {
if !c.isPrivate() {
nonPrivateContact.append(contact)
}
}
But I want to keep the static keyword
This looks like a bug or a non-supported feature. I would expect that
the following works:
if let gsType = contact.dynamicType as? GroupStatus.Type {
if gsType.isPrivate() {
// ...
}
}
However, it does not compile:
error: accessing members of protocol type value 'GroupStatus.Type' is unimplemented
It does compile with FamilyContact.Type instead of GroupStatus.Type. A similar problem is reported here:
Swift 1.1 and 1.2: accessing members of protocol type value XXX.Type' is unimplemented
Making isPrivate() an instance method instead of a class method is
the only workaround that I currently can think of, maybe someone comes
with a better solution ...
Update for Swift 2 / Xcode 7: As #Tankista noted below, this has
been fixed. The above code compiles and works as expected in Xcode 7 beta 3.
type(of: contact).isPrivate()
This should work in recent Swift.

Resources