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: } } }