Browse Source

Init commit

Joachim M. Giæver 4 years ago
parent
commit
4b57b3183c
6 changed files with 337 additions and 0 deletions
  1. 31 0
      conn/connect.go
  2. 26 0
      field.go
  3. 67 0
      mappable.go
  4. 87 0
      mapper.go
  5. 15 0
      relaltions.go
  6. 111 0
      table.go

+ 31 - 0
conn/connect.go

@@ -0,0 +1,31 @@
+package conn
+
+import (
+	"context"
+	"fmt"
+
+	"git.giaever.org/bnb.hosting/database/config"
+	_ "github.com/go-sql-driver/mysql"
+	"github.com/jmoiron/sqlx"
+)
+
+type DB struct {
+	*sqlx.DB
+}
+
+func Connect(ctx context.Context) (*DB, error) {
+	db, err := sqlx.ConnectContext(ctx, "mysql", fmt.Sprintf(
+		"%s:%s@%s(%s:%d)/%s%s",
+		config.USER,
+		config.PASS,
+		config.PROTOCOL,
+		config.HOST,
+		config.PORT,
+		config.DATABASE,
+		config.OPTIONS,
+	))
+
+	return &DB{
+		db,
+	}, err
+}

+ 26 - 0
field.go

@@ -0,0 +1,26 @@
+package orm
+
+import (
+	"reflect"
+	"strings"
+)
+
+type field struct {
+	name string
+	ref  string
+	typ  reflect.Kind
+}
+
+func (f field) String() string {
+	return f.name + " (" + f.ref + "|" + f.typ.String() + ")"
+}
+
+type fields []field
+
+func (fs fields) String() string {
+	s := []string{}
+	for _, f := range fs {
+		s = append(s, f.String())
+	}
+	return strings.Join(s, ",")
+}

+ 67 - 0
mappable.go

@@ -0,0 +1,67 @@
+package orm
+
+import (
+	"strings"
+
+	"git.giaever.org/bnb.hosting/orm/conn"
+	"github.com/go-openapi/inflect"
+)
+
+type MappableInterface interface {
+	SetDb(*conn.DB) MappableInterface
+	GetDb() *conn.DB
+	GetTableMapperFn() MapperFn
+	GetFieldMapperFn() MapperFn
+}
+
+type MapperFn func(string) string
+
+type Mappable struct {
+	db *conn.DB `db:"omit"`
+}
+
+func (m *Mappable) SetDb(db *conn.DB) MappableInterface {
+	m.db = db
+	return m
+}
+
+func (m *Mappable) GetDb() *conn.DB {
+	return m.db
+}
+
+func (m Mappable) GetTableMapperFn() MapperFn {
+	return func(t string) string {
+		s := []byte{}
+		for i := 0; i < len(t); i++ {
+			c := t[i]
+			if c >= 'A' && c <= 'Z' {
+				if i != 0 {
+					s = append(s, '_')
+				}
+				c = c + ('a' - 'A')
+			}
+			s = append(s, c)
+		}
+
+		str := strings.Split((string)(s), "_")
+		str[len(str)-1] = inflect.Pluralize(str[len(str)-1])
+		return strings.Join(str, "_")
+	}
+}
+
+func (m Mappable) GetFieldMapperFn() MapperFn {
+	return func(f string) string {
+		s := []byte{}
+		for i := 0; i < len(f); i++ {
+			c := f[i]
+			if c >= 'A' && c <= 'Z' {
+				if i != 0 {
+					s = append(s, '_')
+				}
+				c = c + ('a' - 'A')
+			}
+			s = append(s, c)
+		}
+		return (string)(s)
+	}
+}

+ 87 - 0
mapper.go

@@ -0,0 +1,87 @@
+package orm
+
+import (
+	"fmt"
+	"reflect"
+	"strings"
+	"sync"
+)
+
+type tblmap map[string]*tbl
+
+func (t tblmap) String() string {
+	s := make([]string, 0)
+	for _, tbl := range t {
+		s = append(s, tbl.String())
+	}
+
+	return strings.Join(s, "\n")
+}
+
+type mapper struct {
+	lock *sync.Mutex
+	wg   *sync.WaitGroup
+	tbls tblmap
+}
+
+var ctx *mapper = &mapper{
+	lock: &sync.Mutex{},
+	wg:   &sync.WaitGroup{},
+	tbls: make(tblmap),
+}
+
+func Map(tbl MappableInterface) *mapper {
+	ctx.wg.Add(1)
+	go func() {
+		t := ctx.addTbl(tbl)
+		if !t.isMapped() {
+			ctx.mapTbl(t)
+		}
+		ctx.wg.Done()
+		t.Unlock()
+	}()
+	return ctx
+}
+
+func WaitInit() {
+	fmt.Println("Waiting in main")
+	ctx.wg.Wait()
+	fmt.Println(ctx.tbls)
+}
+
+func (m *mapper) addTbl(t MappableInterface) *tbl {
+	rt := reflect.TypeOf(t).Elem()
+
+	m.lock.Lock()
+	defer m.lock.Unlock()
+
+	if t, ok := m.tbls[rt.Name()]; ok {
+		return t.ReadLock()
+	}
+
+	m.tbls[rt.Name()] = &tbl{
+		rt:     rt,
+		rv:     reflect.ValueOf(t).Elem(),
+		lock:   &sync.RWMutex{},
+		tFn:    t.GetTableMapperFn(),
+		fFn:    t.GetFieldMapperFn(),
+		mapped: false,
+	}
+
+	return m.tbls[rt.Name()].WriteLock()
+}
+
+func (m *mapper) mapTbl(t *tbl) {
+	for n := 0; n < t.getType().NumField(); n++ {
+		switch t.getType().Kind() {
+		case reflect.Ptr:
+		case reflect.Struct:
+			if f := t.getType().Field(n); !f.Anonymous {
+				t.add(t.getType().Field(n))
+			} else if t.getType().Field(n).Anonymous && t.getValue().Field(n).CanInterface() {
+				t.add(t.getType().Field(n))
+			}
+		default:
+		}
+	}
+}

+ 15 - 0
relaltions.go

@@ -0,0 +1,15 @@
+package orm
+
+type relType int8
+
+const (
+	hasOne    relType = iota << 1
+	hasMany   relType = iota << 1
+	belongsTo relType = iota << 1
+)
+
+type rel struct {
+	*tbl
+}
+
+type relations map[relType]*rel

+ 111 - 0
table.go

@@ -0,0 +1,111 @@
+package orm
+
+import (
+	"fmt"
+	"math/rand"
+	"reflect"
+	"strings"
+	"sync"
+	"time"
+)
+
+type tbl struct {
+	rt     reflect.Type
+	rv     reflect.Value
+	lock   *sync.RWMutex
+	name   string
+	tFn    MapperFn
+	fFn    MapperFn
+	f      fields
+	rel    relations
+	mapped bool
+}
+
+func (t *tbl) GetName() string {
+	t.ReadLock()
+	defer t.Unlock()
+	return t.getName()
+}
+
+func (t *tbl) getName() string {
+	return t.getType().Name()
+}
+
+func (t *tbl) GetTableName() string {
+	t.ReadLock()
+	defer t.Unlock()
+	return t.getTable()
+}
+
+func (t *tbl) getTable() string {
+	if len(t.name) == 0 {
+		t.name = t.tFn(t.getType().Name())
+	}
+	return t.name
+}
+
+func (t *tbl) String() string {
+	return fmt.Sprintf("%s (`%s`):%s",
+		t.getName(), t.getTable(),
+		func() string {
+			s := strings.Split(t.f.String(), ",")
+			if len(s) <= 1 {
+				return " " + t.f.String()
+			}
+
+			return "\n\t" + strings.Join(s, ",\n\t")
+		}(),
+	)
+}
+
+func (t *tbl) add(r reflect.StructField) {
+	switch r.Type.Kind() {
+	case reflect.Ptr:
+		fmt.Println("Ptr", r)
+	case reflect.Map:
+		fmt.Println("Map", r)
+	case reflect.Struct:
+		fmt.Println("Struct", r)
+	default:
+		t.f = append(t.f, field{r.Name, t.fFn(r.Name), r.Type.Kind()})
+	}
+}
+
+func (t *tbl) getType() reflect.Type {
+	return t.rt
+}
+
+func (t *tbl) getValue() reflect.Value {
+	return t.rv
+}
+
+func (t *tbl) isMapped() bool {
+	return t.mapped
+}
+
+func (t *tbl) ReadLock() *tbl {
+	t.lock.RLock()
+	return t
+}
+
+func (t *tbl) WriteLock() *tbl {
+	if t.mapped {
+		return nil
+	}
+	t.lock.Lock()
+	return t
+}
+
+func (t *tbl) Unlock() {
+	if !t.mapped {
+		t.mapped = true
+		t.lock.Unlock()
+		return
+	}
+	t.lock.RUnlock()
+}
+
+func (t *tbl) randomWork(wg *sync.WaitGroup) *tbl {
+	time.Sleep((time.Duration)(rand.Intn(100)*rand.Intn(100)) * time.Millisecond)
+	return t
+}