Skip to content

Commit

Permalink
feat(cmfx/relationship): 添加 relationship 包
Browse files Browse the repository at this point in the history
  • Loading branch information
caixw committed Jan 8, 2025
1 parent 90c8eb3 commit 41f2820
Show file tree
Hide file tree
Showing 4 changed files with 199 additions and 0 deletions.
12 changes: 12 additions & 0 deletions cmfx/relationship/models.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// SPDX-FileCopyrightText: 2025 caixw
//
// SPDX-License-Identifier: MIT

package relationship

type relationshipPO[T1, T2 T] struct {
V1 T1 `orm:"name(v1);unique(v12)"`
V2 T2 `orm:"name(v2);unique(v12)"`
}

func (*relationshipPO[T1, T2]) TableName() string { return "_relationships" }
87 changes: 87 additions & 0 deletions cmfx/relationship/module.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// SPDX-FileCopyrightText: 2025 caixw
//
// SPDX-License-Identifier: MIT

package relationship

import (
"github.com/issue9/orm/v6"
"github.com/issue9/orm/v6/fetch"
"github.com/issue9/web"

"github.com/issue9/cmfx/cmfx"
)

type Module[T1, T2 T] struct {
db *orm.DB
mod *cmfx.Module
}

func Load[T1, T2 T](mod *cmfx.Module, prefix string) *Module[T1, T2] {
return &Module[T1, T2]{
db: buildDB(mod, prefix),
mod: mod,
}
}

func Install[T1, T2 T](mod *cmfx.Module, prefix string) *Module[T1, T2] {
db := buildDB(mod, prefix)
if err := db.Create(&relationshipPO[T1, T2]{}); err != nil {
panic(web.SprintError(mod.Server().Locale().Printer(), true, err))
}

return Load[T1, T2](mod, prefix)
}

func (m *Module[T1, T2]) engine(tx *orm.Tx) orm.Engine {
if tx == nil {
return m.db
}
return tx.NewEngine(m.db.TablePrefix())
}

func (m *Module[T1, T2]) Add(tx *orm.Tx, v1 T1, v2 T2) error {
_, err := m.engine(tx).Insert(&relationshipPO[T1, T2]{V1: v1, V2: v2})
return err
}

func (m *Module[T1, T2]) Delete(tx *orm.Tx, v1 T1, v2 T2) error {
_, err := m.engine(tx).Delete(&relationshipPO[T1, T2]{V1: v1, V2: v2})
return err
}

func (m *Module[T1, T2]) DeleteByV1(tx *orm.Tx, v1 T1) error {
_, err := m.engine(tx).Where("v1=?", v1).Delete(&relationshipPO[T1, T2]{})
return err
}

func (m *Module[T1, T2]) DeleteByV2(tx *orm.Tx, v2 T2) error {
_, err := m.engine(tx).Where("v2=?", v2).Delete(&relationshipPO[T1, T2]{})
return err
}

func (m *Module[T1, T2]) CountByV1(v1 T1) (int64, error) {
return m.db.Where("v1=?", v1).Count(&relationshipPO[T1, T2]{})
}

func (m *Module[T1, T2]) CountByV2(v2 T2) (int64, error) {
return m.db.Where("v2=?", v2).Count(&relationshipPO[T1, T2]{})
}

// ListV1 列出所有与 v2 关联的 v1 列表
func (m *Module[T1, T2]) ListV1(v2 T2) ([]T1, error) {
rows, err := m.db.SQLBuilder().Select().From(orm.TableName(&relationshipPO[T1, T2]{})).Where("v2=?", v2).Query()
if err != nil {
return nil, err
}
return fetch.Column[T1](false, "v1", rows)
}

// ListV2 列出所有与 v1 关联的 v2 列表
func (m *Module[T1, T2]) ListV2(v1 T1) ([]T2, error) {
rows, err := m.db.SQLBuilder().Select().From(orm.TableName(&relationshipPO[T1, T2]{})).Where("v1=?", v1).Query()
if err != nil {
return nil, err
}
return fetch.Column[T2](false, "v2", rows)
}
79 changes: 79 additions & 0 deletions cmfx/relationship/module_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// SPDX-FileCopyrightText: 2025 caixw
//
// SPDX-License-Identifier: MIT

package relationship

import (
"testing"

"github.com/issue9/assert/v4"

"github.com/issue9/cmfx/cmfx/initial/test"
)

func TestInstall(t *testing.T) {
a := assert.New(t, false)
suite := test.NewSuite(a)
defer suite.Close()

mod := suite.NewModule("rbac")
Install[string, int](mod, "t1_t2")

suite.TableExists(mod.ID() + "_t1_t2_relationships")
}

func TestModule(t *testing.T) {
a := assert.New(t, false)
s := test.NewSuite(a)
defer s.Close()

mod := s.NewModule("rbac")
m := Install[string, int](mod, "t1_t2")

// Add

a.NotError(m.Add(nil, "v", 1))
a.NotError(m.Add(nil, "v", 2))
a.NotError(m.Add(nil, "v", 3))

// Count

cnt, err := m.CountByV1("v")
a.NotError(err).Equal(cnt, 3)

cnt, err = m.CountByV2(3)
a.NotError(err).Equal(cnt, 1)

cnt, err = m.CountByV2(100)
a.NotError(err).Equal(cnt, 0)

// List

list1, err := m.ListV1(2)
a.NotError(err).Equal(list1, []string{"v"})

list2, err := m.ListV2("v")
a.NotError(err).Equal(list2, []int{1, 2, 3})

list2, err = m.ListV2("vv") // 不存在的数据
a.NotError(err).Equal(list2, []int{})

// Delete

a.NotError(m.Delete(nil, "v", 1))
cnt, err = m.CountByV1("v")
a.NotError(err).Equal(cnt, 2) // 删除了一条

a.NotError(m.Delete(nil, "vv", 2)) // 不存在
cnt, err = m.CountByV1("v")
a.NotError(err).Equal(cnt, 2)

a.NotError(m.DeleteByV2(nil, 2))
cnt, err = m.CountByV1("v")
a.NotError(err).Equal(cnt, 1)

a.NotError(m.DeleteByV1(nil, "v"))
cnt, err = m.CountByV1("v")
a.NotError(err).Equal(cnt, 0)
}
21 changes: 21 additions & 0 deletions cmfx/relationship/relationship.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// SPDX-FileCopyrightText: 2025 caixw
//
// SPDX-License-Identifier: MIT

// Package relationship 用于处理多对多的数据表关系
package relationship

import (
"github.com/issue9/orm/v6"

"github.com/issue9/cmfx/cmfx"
)

// T 限制了可用的字段类型
type T interface {
~string | ~int | ~int64
}

func buildDB(mod *cmfx.Module, tableName string) *orm.DB {
return mod.DB().New(mod.DB().TablePrefix() + "_" + tableName)
}

0 comments on commit 41f2820

Please sign in to comment.