Ejemplo n.º 1
0
// Field is a conveniency function which returns a reference to a field
// to be used in a query, mostly used for joins.
func F(field string) query.F {
	return query.F(field)
}
Ejemplo n.º 2
0
// Initialize is a low level function and should only be used
// when dealing with multiple ORM types. If you're only using the
// default ORM as returned by gnd.la/app.App.Orm() or
// gnd.la/app.Context.Orm() you should not call this function
// manually.
//
// Initialize resolves model references and creates tables and
// indexes required by the registered models. You MUST call it
// AFTER all the models have been registered and BEFORE starting
// to use the ORM for queries for each ORM type.
func (o *Orm) Initialize() error {
	globalRegistry.Lock()
	defer globalRegistry.Unlock()
	Signals.WillInitialize.emit(o)
	if err := o.initializePending(); err != nil {
		return err
	}
	nr := globalRegistry.names[o.tags]
	// Resolve references
	names := make(map[string]*model)
	for _, v := range nr {
		names[v.name] = v
	}
	for _, v := range nr {
		if c := len(v.references); c > 0 {
			v.fields.References = make(map[string]*driver.Reference, c)
			for k, r := range v.references {
				referenced := names[r.model]
				if referenced == nil {
					if !strings.Contains(r.model, ".") {
						referenced = names[v.Type().PkgPath()+"."+r.model]
					}
					if referenced == nil {
						return fmt.Errorf("can't find referenced model %q from model %q", r.model, v.name)
					}
				}
				if r.field == "" {
					// Map to PK
					if pk := referenced.fields.PrimaryKey; pk >= 0 {
						r.field = referenced.fields.QNames[pk]
					} else {
						return fmt.Errorf("referenced model %q does not have a non-composite primary key. Please, specify a field", r.model)
					}
				}
				_, ft, err := v.fields.Map(k)
				if err != nil {
					return err
				}
				_, fkt, err := referenced.fields.Map(r.field)
				if err != nil {
					return err
				}
				if ft != fkt {
					return fmt.Errorf("type mismatch: referenced field %q in model %q is of type %s, field %q in model %q is of type %s",
						r.field, referenced.name, fkt, k, v.name, ft)
				}
				v.fields.References[k] = &driver.Reference{
					Model: referenced,
					Field: r.field,
				}
				if v.modelReferences == nil {
					v.modelReferences = make(map[*model][]*join)
				}
				v.modelReferences[referenced] = append(v.modelReferences[referenced], &join{
					model: &joinModel{model: referenced},
					q:     Eq(v.fullName(k), query.F(referenced.fullName(r.field))),
				})
				if v.namedReferences == nil {
					v.namedReferences = make(map[string]*model)
				}
				v.namedReferences[referenced.name] = referenced
				v.namedReferences[referenced.shortName] = referenced
				if referenced.modelReferences == nil {
					referenced.modelReferences = make(map[*model][]*join)
				}
				referenced.modelReferences[v] = append(referenced.modelReferences[v], &join{
					model: &joinModel{model: v},
					q:     Eq(referenced.fullName(r.field), query.F(v.fullName(k))),
				})
				if referenced.namedReferences == nil {
					referenced.namedReferences = make(map[string]*model)
				}
				referenced.namedReferences[v.name] = v
				referenced.namedReferences[v.shortName] = v
			}
		}
	}
	models := make([]driver.Model, 0, len(nr))
	for _, v := range nr {
		models = append(models, v)
	}
	// Sort models to the ones with FKs are created after
	// the models they reference
	sort.Sort(sortModels(models))
	return o.driver.Initialize(models)
}