Skip to content

Commit

Permalink
less panics
Browse files Browse the repository at this point in the history
  • Loading branch information
amirrezaask committed Mar 15, 2022
1 parent 3e0a2ca commit 0e12943
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 30 deletions.
31 changes: 19 additions & 12 deletions orm.go
Original file line number Diff line number Diff line change
Expand Up @@ -359,15 +359,16 @@ type HasManyConfig struct {
// HasMany[Comment](&Post{})
// is for Post HasMany Comment relationship.
func HasMany[PROPERTY Entity](owner Entity) *QueryBuilder[PROPERTY] {
q := NewQueryBuilder[PROPERTY]()
outSchema := getSchemaFor(*new(PROPERTY))
// getting config from our cache
c, ok := getSchemaFor(owner).relations[outSchema.Table].(HasManyConfig)
if !ok {
panic("wrong config passed for HasMany")
q.err = fmt.Errorf("wrong config passed for HasMany")
}

s := getSchemaFor(owner)
return NewQueryBuilder[PROPERTY]().
return q.
SetDialect(s.getDialect()).
Table(c.PropertyTable).
Select(outSchema.Columns(true)...).
Expand All @@ -394,15 +395,19 @@ type HasOneConfig struct {
// HasOne[HeaderPicture](&Post{})
// is for Post HasOne HeaderPicture relationship.
func HasOne[PROPERTY Entity](owner Entity) *QueryBuilder[PROPERTY] {
q := NewQueryBuilder[PROPERTY]()
property := getSchemaFor(*new(PROPERTY))
c, ok := getSchemaFor(owner).relations[property.Table].(HasOneConfig)
if !ok {
panic("wrong config passed for HasOne")
q.err = fmt.Errorf("wrong config passed for HasOne")
}

//settings default config Values
return NewQueryBuilder[PROPERTY]().SetDialect(property.getDialect()).Table(c.PropertyTable).
Select(property.Columns(true)...).Where(c.PropertyForeignKey, genericGetPKValue(owner))
return q.
SetDialect(property.getDialect()).
Table(c.PropertyTable).
Select(property.Columns(true)...).
Where(c.PropertyForeignKey, genericGetPKValue(owner))
}

//BelongsToConfig contains all information we need for a BelongsTo relationship
Expand All @@ -428,10 +433,11 @@ type BelongsToConfig struct {
//OWNER type parameter and property argument, so
//property BelongsTo OWNER.
func BelongsTo[OWNER Entity](property Entity) *QueryBuilder[OWNER] {
q := NewQueryBuilder[OWNER]()
owner := getSchemaFor(*new(OWNER))
c, ok := getSchemaFor(property).relations[owner.Table].(BelongsToConfig)
if !ok {
panic("wrong config passed for BelongsTo")
q.err = fmt.Errorf("wrong config passed for BelongsTo")
}

ownerIDidx := 0
Expand All @@ -443,7 +449,7 @@ func BelongsTo[OWNER Entity](property Entity) *QueryBuilder[OWNER] {

ownerID := genericValuesOf(property, true)[ownerIDidx]

return NewQueryBuilder[OWNER]().
return q.
SetDialect(owner.getDialect()).
Table(c.OwnerTable).Select(owner.Columns(true)...).
Where(c.ForeignColumnName, ownerID)
Expand Down Expand Up @@ -485,12 +491,13 @@ type BelongsToManyConfig struct {

//BelongsToMany configures a QueryBuilder for a BelongsToMany relationship
func BelongsToMany[OWNER Entity](property Entity) *QueryBuilder[OWNER] {
q := NewQueryBuilder[OWNER]()
out := new(OWNER)
c, ok := getSchemaFor(property).relations[getSchemaFor(*out).Table].(BelongsToManyConfig)
if !ok {
panic("wrong config passed for HasMany")
q.err = fmt.Errorf("wrong config passed for HasMany")
}
return NewQueryBuilder[OWNER]().
return q.
Select(getSchemaFor(*out).Columns(true)...).
Table(getSchemaFor(*out).Table).
WhereIn(c.OwnerLookupColumn, Raw(fmt.Sprintf(`SELECT %s FROM %s WHERE %s = ?`,
Expand All @@ -515,7 +522,7 @@ func Add(to Entity, items ...Entity) error {
case HasOneConfig:
return addProperty(to, items[0])
case BelongsToManyConfig:
panic("not implemented yet")
return fmt.Errorf("adding to a belongs to many relation is not implemented yet")
default:
return fmt.Errorf("cannot add for relation: %T", rels[getSchemaFor(items[0]).Table])
}
Expand Down Expand Up @@ -554,7 +561,7 @@ func addProperty(to Entity, items ...Entity) error {
for _, item := range items {
vals := genericValuesOf(item, false)
if cols[ownerPKIdx] != getSchemaFor(items[0]).relations[getSchemaFor(to).Table].(BelongsToConfig).LocalForeignKey {
panic("owner pk idx is not correct")
return fmt.Errorf("owner pk idx is not correct")
}
vals[ownerPKIdx] = ownerPK
i.Values = append(i.Values, vals)
Expand All @@ -568,7 +575,7 @@ func addProperty(to Entity, items ...Entity) error {
for _, item := range items {
vals := genericValuesOf(item, false)
if cols[ownerPKIdx] != getSchemaFor(items[0]).relations[getSchemaFor(to).Table].(BelongsToConfig).LocalForeignKey {
panic("owner pk idx is not correct")
return fmt.Errorf("owner pk idx is not correct")
}
vals = append(vals[:ownerPKIdx+1], vals[ownerPKIdx:]...)
vals[ownerPKIdx] = ownerPK
Expand Down
57 changes: 39 additions & 18 deletions query.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,10 @@ func (d *QueryBuilder[E]) toSqlDelete() (string, []interface{}, error) {
var args []interface{}
if d.where != nil {
d.where.PlaceHolderGenerator = d.placeholderGenerator
where, whereArgs := d.where.ToSql()
where, whereArgs, err := d.where.ToSql()
if err != nil {
return "", nil, err
}
base += " WHERE " + where
args = append(args, whereArgs...)
}
Expand Down Expand Up @@ -225,7 +228,10 @@ func (u *QueryBuilder[E]) toSqlUpdate() (string, []interface{}, error) {
args := u.args()
if u.where != nil {
u.where.PlaceHolderGenerator = u.placeholderGenerator
where, whereArgs := u.where.ToSql()
where, whereArgs, err := u.where.ToSql()
if err != nil {
return "", nil, err
}
args = append(args, whereArgs...)
base += " WHERE " + where
}
Expand All @@ -246,9 +252,9 @@ func (s *QueryBuilder[E]) toSqlSelect() (string, []interface{}, error) {
base += " " + s.selected.String()
// from
if s.table == "" && s.subQuery == nil {
panic("Table name cannot be empty")
return "", nil, fmt.Errorf("Table name cannot be empty")
} else if s.table != "" && s.subQuery != nil {
panic("cannot have both Table and subquery")
return "", nil, fmt.Errorf("cannot have both Table and subquery")
}
if s.table != "" {
base += " " + "FROM " + s.table
Expand All @@ -272,7 +278,10 @@ func (s *QueryBuilder[E]) toSqlSelect() (string, []interface{}, error) {
// whereClause
if s.where != nil {
s.where.PlaceHolderGenerator = s.placeholderGenerator
where, whereArgs := s.where.ToSql()
where, whereArgs, err := s.where.ToSql()
if err != nil {
return "", nil, err
}
base += " WHERE " + where
args = append(args, whereArgs...)
}
Expand Down Expand Up @@ -303,6 +312,9 @@ func (s *QueryBuilder[E]) toSqlSelect() (string, []interface{}, error) {
//ToSql creates sql query from QueryBuilder based on internal fields it would decide what kind
//of query to build.
func (q *QueryBuilder[E]) ToSql() (string, []interface{}, error) {
if q.err != nil {
return "", nil, q.err
}
if q.typ == queryType_SELECT {
return q.toSqlSelect()
} else if q.typ == queryType_Delete {
Expand Down Expand Up @@ -476,7 +488,8 @@ func (q *QueryBuilder[E]) Where(parts ...interface{}) *QueryBuilder[E] {
q.where = &whereClause{raw: r.sql, args: r.args, PlaceHolderGenerator: q.placeholderGenerator}
return q
} else {
panic("when you have one argument passed to where, it should be *raw")
q.err = fmt.Errorf("when you have one argument passed to where, it should be *raw")
return q
}

} else if len(parts) == 2 {
Expand All @@ -493,7 +506,8 @@ func (q *QueryBuilder[E]) Where(parts ...interface{}) *QueryBuilder[E] {
q.where = &whereClause{cond: cond{Lhs: parts[0].(string), Op: binaryOp(parts[1].(string)), Rhs: parts[2:]}, PlaceHolderGenerator: q.placeholderGenerator}
return q
} else {
panic("wrong number of arguments passed to Where")
q.err = fmt.Errorf("wrong number of arguments passed to Where")
return q
}
}

Expand All @@ -519,22 +533,22 @@ type cond struct {
Rhs interface{}
}

func (b cond) ToSql() (string, []interface{}) {
func (b cond) ToSql() (string, []interface{}, error) {
var phs []string
if b.Op == In {
rhs, isInterfaceSlice := b.Rhs.([]interface{})
if isInterfaceSlice {
phs = b.PlaceHolderGenerator(len(rhs))
return fmt.Sprintf("%s IN (%s)", b.Lhs, strings.Join(phs, ",")), rhs
return fmt.Sprintf("%s IN (%s)", b.Lhs, strings.Join(phs, ",")), rhs, nil
} else if rawThing, isRaw := b.Rhs.(*raw); isRaw {
return fmt.Sprintf("%s IN (%s)", b.Lhs, rawThing.sql), rawThing.args
return fmt.Sprintf("%s IN (%s)", b.Lhs, rawThing.sql), rawThing.args, nil
} else {
panic("Right hand side of Cond when operator is IN should be either a interface{} slice or *raw")
return "", nil, fmt.Errorf("Right hand side of Cond when operator is IN should be either a interface{} slice or *raw")
}

} else {
phs = b.PlaceHolderGenerator(1)
return fmt.Sprintf("%s %s %s", b.Lhs, b.Op, pop(&phs)), []interface{}{b.Rhs}
return fmt.Sprintf("%s %s %s", b.Lhs, b.Op, pop(&phs)), []interface{}{b.Rhs}, nil
}
}

Expand All @@ -552,27 +566,34 @@ type whereClause struct {
args []interface{}
}

func (w whereClause) ToSql() (string, []interface{}) {
func (w whereClause) ToSql() (string, []interface{}, error) {
var base string
var args []interface{}
var err error
if w.raw != "" {
base = w.raw
args = w.args
} else {
w.cond.PlaceHolderGenerator = w.PlaceHolderGenerator
base, args = w.cond.ToSql()
base, args, err = w.cond.ToSql()
if err != nil {
return "", nil, err
}
}
if w.next == nil {
return base, args
return base, args, nil
}
if w.next != nil {
next, nextArgs := w.next.ToSql()
next, nextArgs, err := w.next.ToSql()
if err != nil {
return "", nil, err
}
base += " " + w.nextTyp + " " + next
args = append(args, nextArgs...)
return base, args
return base, args, nil
}

return base, args
return base, args, nil
}

//WhereIn adds a where clause to QueryBuilder using In operator.
Expand Down

0 comments on commit 0e12943

Please sign in to comment.