You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: session_find.go
    path of file: ./repos/xorm
    
    the code of the file until where you have to start completion: // Copyright 2016 The Xorm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package xorm

import (
	"errors"
	"fmt"
	"reflect"

	"github.com/xormplus/builder"
	"github.com/xormplus/xorm/caches"
	"github.com/xormplus/xorm/core"
	"github.com/xormplus/xorm/internal/statements"
	"github.com/xormplus/xorm/internal/utils"
	"github.com/xormplus/xorm/schemas"
)

const (
	tpStruct = iota
	tpNonStruct
)

// Find retrieve records from table, condiBeans's non-empty fields
// are conditions. beans could be []Struct, []*Struct, map[int64]Struct
// map[int64]*Struct
func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{}) error {
	if session.isAutoClose {
		defer session.Close()
	}
	return session.find(rowsSlicePtr, condiBean...)
}

// FindAndCount find the results and also return the counts
func (session *Session) FindAndCount(rowsSlicePtr interface{}, condiBean ...interface{}) (int64, error) {
	if session.isAutoClose {
		defer session.Close()
	}

	if session.isSqlFunc {
		session.autoResetStatement = false
		err := session.find(rowsSlicePtr, condiBean...)
		if err != nil {
			return 0, err
		}

		var sql = session.statement.RawSQL
		session.autoResetStatement = true
		sql = "select count(1) from (" + sql + ") t"
		var count int64
		_, err = session.SQL(sql).Get(&count)
		if err != nil {
			return 0, err
		}
		return count, nil

	} else {
		session.autoResetStatement = false
		err := session.find(rowsSlicePtr, condiBean...)
		if err != nil {
			return 0, err
		}

		sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))
		if sliceValue.Kind() != reflect.Slice && sliceValue.Kind() != reflect.Map {
			return 0, errors.New("needs a pointer to a slice or a map")
		}

		sliceElementType := sli
    
func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr interface{}, args ...interface{}) (err error) {
	if !session.canCache() ||
		utils.IndexNoCase(sqlStr, "having") != -1 ||
		utils.IndexNoCase(sqlStr, "group by") != -1 {
		return ErrCacheFailed
	}

	tableName := session.statement.TableName()
	cacher := session.engine.cacherMgr.GetCacher(tableName)
	if cacher == nil {
		return nil
	}

	for _, filter := range session.engine.dialect.Filters() {
		sqlStr = filter.Do(sqlStr)
	}

	newsql := session.statement.ConvertIDSQL(sqlStr)
	if newsql == "" {
		return ErrCacheFailed
	}

	table := session.statement.RefTable
	ids, err := caches.GetCacheSql(cacher, tableName, newsql, args)
	if err != nil {
		rows, err := session.queryRows(newsql, args...)
		if err != nil {
			return err
		}
		defer rows.Close()

		var i int
		ids = make([]schemas.PK, 0)
		for rows.Next() {
			i++
			if i > 500 {
				session.engine.logger.Debugf("[cacheFind] ids length > 500, no cache")
				return ErrCacheFailed
			}
			var res = make([]string, len(table.PrimaryKeys))
			err = rows.ScanSlice(&res)
			if err != nil {
				return err
			}
			var pk schemas.PK = make([]interface{}, len(table.PrimaryKeys))
			for i, col := range table.PKColumns() {
				pk[i], err = col.ConvertID(res[i])
				if err != nil {
					return err
				}
			}

			ids = append(ids, pk)
		}

		session.engine.logger.Debugf("[cache] cache sql: %v, %v, %v, %v, %v", ids, tableName, sqlStr, newsql, args)
		err = caches.PutCacheSql(cacher, ids, tableName, newsql, args)
		if err != nil {
			return err
		}
	} else {
		session.engine.logger.Debugf("[cache] cache hit sql: %v, %v, %v, %v", tableName, sqlStr, newsql, args)
	}

	sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr))

	ididxes := make(map[string]int)
	var ides []schemas.PK
	var temps = make([]interface{}, len(ids))

	for idx, id := range ids {
		sid, err := id.ToString()
		if err != nil {
			return err
		}
		bean := cacher.GetBean(tableName, sid)

		isHit := func() (ht bool) {
			if bean == nil {
				ht = false
				return
			}
			ckb := reflect.ValueOf(bean).Elem().Type()
			ht = ckb == t
			if !ht && t.Kind() == reflect.Ptr {
				ht = t.Elem() == ckb
			}
			return
		}
		if !isHit() {
			ides = append(ides, id)
			ididxes[sid] = idx
		} else {
			session.engine.logger.Debugf("[cache] cache hit bean: %v, %v, %v", tableName, id, bean)

			pk, err := table.IDOfV(reflect.ValueOf(bean))
			if err != nil {
				return err
			}

			xid, err := pk.ToString()
			if err != nil {
				return err
			}

			if sid != xid {
				session.engine.logger.Errorf("[cache] error cache: %v, %v, %v", xid, sid, bean)
				return ErrCacheFailed
			}
			temps[idx] = bean
		}
	}

	if len(ides) > 0 {
		slices := reflect.New(reflect.SliceOf(t))
		beans := slices.Interface()

		statement := session.statement
		session.statement = statements.NewStatement(
			session.engine.dialect,
			session.engine.tagParser,
			session.engine.DatabaseTZ,
		)
		if len(table.PrimaryKeys) == 1 {
			ff := make([]interface{}, 0, len(ides))
			for _, ie := range ides {
				ff = append(ff, ie[0])
			}

			session.In("`"+table.PrimaryKeys[0]+"`", ff...)
		} else {
			for _, ie := range ides {
				cond := builder.NewCond()
				for i, name := range table.PrimaryKeys {
					cond = cond.And(builder.Eq{"`" + name + "`": ie[i]})
				}
				session.Or(cond)
			}
		}

		err = session.NoCache().Table(tableName).find(beans)
		if err != nil {
			return err
		}

		session.statement = statement

		vs := reflect.Indirect(reflect.ValueOf(beans))
		for i := 0; i < vs.Len(); i++ {
			rv := vs.Index(i)
			if rv.Kind() != reflect.Ptr {
				rv = rv.Addr()
			}
			id, err := table.IDOfV(rv)
			if err != nil {
				return err
			}
			sid, err := id.ToString()
			if err != nil {
				return err
			}

			bean := rv.Interface()
			temps[ididxes[sid]] = bean
			session.engine.logger.Debugf("[cache] cache bean: %v, %v, %v, %v", tableName, id, bean, temps)
			cacher.PutBean(tableName, sid, bean)
		}
	}

	for j := 0; j < len(temps); j++ {
		bean := temps[j]
		if bean == nil {
			session.engine.logger.Warnf("[cache] cache no hit: %v, %v, %v", tableName, ids[j], temps)
			// return errors.New("cache error") // !nashtsai! no need to return error, but continue instead
			continue
		}
		if sliceValue.Kind() == reflect.Slice {
			if t.Kind() == reflect.Ptr {
				sliceValue.Set(reflect.Append(sliceValue, reflect.ValueOf(bean)))
			} else {
				sliceValue.Set(reflect.Append(sliceValue, reflect.Indirect(reflect.ValueOf(bean))))
			}
		} else if sliceValue.Kind() == reflect.Map {
			var key = ids[j]
			keyType := sliceValue.Type().Key()
			var ikey interface{}
			if len(key) == 1 {
				ikey, err = str2PK(fmt.Sprintf("%v", key[0]), keyType)
				if err != nil {
					return err
				}
			} else {
				if keyType.Kind() != reflect.Slice {
					return errors.New("table have multiple primary keys, key is not schemas.PK or slice")
				}
				ikey = key
			}

			if t.Kind() == reflect.Ptr {
				sliceValue.SetMapIndex(reflect.ValueOf(ikey), reflect.ValueOf(bean))
			} else {
				sliceValue.SetMapIndex(reflect.ValueOf(ikey), reflect.Indirect(reflect.ValueOf(bean)))
			}
		}
	}

	return nil
}