vapor fluent[sqlite] relations

weixin_33686714發表於2018-10-04

父子關係/一對多/Parent-Child/one-many

星系中有很多恆星,怎麼表示這種關係呢?


1635153-7e29616b068abdc8.png
image.png
struct Galaxy: SQLiteModel {
    var id:Int? = nil
    var name: String
}
struct Planet: SQLiteModel {
    var id: Int?
    var name: String
    var galaxyID: Int
}

fluent 中通過extension在其中新增Parent和Children來實現這種特殊的關聯關係

extension Galaxy{
    var planets: Children<Galaxy, Planet>{
        return children(\.galaxyID)
    }
}

extension Planet{
    var galaxy: Parent<Planet, Galaxy>{
        return parent(\.galaxyID)
    }
}

其中Parent和Children都是一種<From, To>的關係通過keypath來明確怎麼關聯

使用

var galaxy: Galaxy?
galaxy?.planets.query(on: <#T##DatabaseConnectable#>)
var planet: Planet?
planet!.galaxy.get(on: <#T##DatabaseConnectable#>)

兄弟關係/多對多/ many-many

在這種關係中是兩個獨立的Model,為了將他們直觀的關聯需要一個第三方的方式將其聯絡起來,我們稱之為pivot
下面我們就來看一例子:搜尋✨時往往會給他們做個標籤---類地行星 液體星球等,那我們怎麼來關聯呢

1635153-b401d7d3a7148726.png
image.png

上圖中是太陽系中星球的表示
我們建立了三個Model--Planet,Tag, PlanetTag:

struct Planet: SQLiteModel {
    var id: Int?
    var name: String
    var galaxyID: Int
}
struct Tag: SQLiteModel {
    var id: Int?
    
    var name: String
}
struct PlanetTag: SQLitePivot {
    static var leftIDKey: WritableKeyPath<PlanetTag, Int> = \.planetID
    
    static var rightIDKey: WritableKeyPath<PlanetTag, Int> = \.tagID
    
    typealias Left = Planet
    
    typealias Right = Tag
    
    var id: Int?
    var planetID: Int
    var tagID: Int
}

PlanetTag作為一箇中間紐帶將Tag和Palnet關聯了起來:我們可以通過這種關係搜尋具有某種Tag的Planet也可以通過Planet來檢視大致發現了哪些型別的星球

同樣的Sibling關係也是通過extension中新增

extension Planet {
    // this planet's related tags
    var tags: Siblings<Planet, Tag, PlanetTag> {
        return siblings()
    }
}
extension Tag {
    // all planets that have this tag
    var planets: Siblings<Tag, Planet, PlanetTag> {
        return siblings()
    }
}

Siblings是一種<From, To, Through>,可以解釋為將A和B通過C進行關聯

使用

var p: Planet?
p?.tags.query(on: <#T##DatabaseConnectable#>)
var tag: Tag?
tag?.planets.query(on: <#T##DatabaseConnectable#>)

修改關聯關係 Modifiable Pivot

Pivot要想具有可修改功能需要conformModifiablePivot

extension PlanetTag: ModifiablePivot {
    init(_ planet: Planet, _ tag: Tag) throws {
        planetID = try planet.requireID()
        tagID = try tag.requireID()
    }
}

使用

let planet: Planet = ...
let tag: Tag = ...
planet.tags.attach(tag, on: ...)

相關文章