// toTerm converts an arbitrary object to a Term, within the context that toTerm // was called on. func (ctx context) toTerm(o interface{}) *p.Term { e := Expr(o) var termType p.Term_TermType arguments := e.args options := map[string]interface{}{} switch e.kind { case literalKind: return ctx.literalToTerm(e.args[0]) case javascriptKind: termType = p.Term_JAVASCRIPT if len(arguments) == 2 { options["timeout"] = arguments[1] arguments = arguments[:1] } case tableKind: termType = p.Term_TABLE // first arg to table must be the database if len(arguments) == 1 { dbExpr := naryOperator(databaseKind, ctx.databaseName) arguments = []interface{}{dbExpr, arguments[0]} } if ctx.useOutdated { options["use_outdated"] = ctx.useOutdated } case betweenKind: termType = p.Term_BETWEEN if len(arguments) == 4 { // last argument is an index options["index"] = arguments[3] arguments = arguments[:3] } case reduceKind: termType = p.Term_REDUCE options["base"] = arguments[2] arguments = arguments[:2] case groupedMapReduceKind: termType = p.Term_GROUPED_MAP_REDUCE options["base"] = arguments[4] arguments = arguments[:4] case eqJoinKind: termType = p.Term_EQ_JOIN options["index"] = arguments[3] arguments = arguments[:3] case updateKind, deleteKind, replaceKind, insertKind: if ctx.durability != "" { options["durability"] = ctx.durability } if ctx.returnValues { options["return_vals"] = true } switch e.kind { case updateKind: termType = p.Term_UPDATE options["non_atomic"] = !ctx.atomic case deleteKind: termType = p.Term_DELETE case replaceKind: termType = p.Term_REPLACE options["non_atomic"] = !ctx.atomic case insertKind: termType = p.Term_INSERT options["upsert"] = ctx.overwrite } case tableCreateKind: termType = p.Term_TABLE_CREATE // last argument is the table spec spec := arguments[len(arguments)-1].(TableSpec) arguments = arguments[:len(arguments)-1] if len(arguments) == 0 { // just spec, need to add database dbExpr := naryOperator(databaseKind, ctx.databaseName) arguments = append(arguments, dbExpr) } arguments = append(arguments, spec.Name) if spec.Datacenter != "" { options["datacenter"] = spec.Datacenter } if spec.PrimaryKey != "" { options["primary_key"] = spec.PrimaryKey } if spec.CacheSize != 0 { options["cache_size"] = spec.CacheSize } if spec.Durability != "" { options["durability"] = spec.Durability } case tableDropKind: termType = p.Term_TABLE_DROP if len(arguments) == 1 { // no database specified, use the session database dbExpr := naryOperator(databaseKind, ctx.databaseName) arguments = []interface{}{dbExpr, arguments[0]} } case tableListKind: termType = p.Term_TABLE_LIST if len(arguments) == 0 { // no database specified, use the session database dbExpr := naryOperator(databaseKind, ctx.databaseName) arguments = append(arguments, dbExpr) } case getAllKind: termType = p.Term_GET_ALL options["index"] = arguments[len(arguments)-1] arguments = arguments[:len(arguments)-1] fmt.Println("arguments:", arguments) case funcKind: return ctx.toFuncTerm(arguments[0], arguments[1].(int)) // special made-up kind to set options on the query case upsertKind: ctx.overwrite = e.args[1].(bool) return ctx.toTerm(e.args[0]) case atomicKind: ctx.atomic = e.args[1].(bool) return ctx.toTerm(e.args[0]) case useOutdatedKind: ctx.useOutdated = e.args[1].(bool) return ctx.toTerm(e.args[0]) case durabilityKind: ctx.durability = e.args[1].(string) return ctx.toTerm(e.args[0]) case returnValuesKind: ctx.returnValues = true return ctx.toTerm(e.args[0]) case jsonKind: termType = p.Term_JSON case mapKind: termType = p.Term_MAP case filterKind: termType = p.Term_FILTER case concatMapKind: termType = p.Term_CONCATMAP case orderByKind: termType = p.Term_ORDERBY case distinctKind: termType = p.Term_DISTINCT case countKind: termType = p.Term_COUNT case unionKind: termType = p.Term_UNION case nthKind: termType = p.Term_NTH case groupByKind: termType = p.Term_GROUPBY case innerJoinKind: termType = p.Term_INNER_JOIN case outerJoinKind: termType = p.Term_OUTER_JOIN case zipKind: termType = p.Term_ZIP case coerceToKind: termType = p.Term_COERCE_TO case typeOfKind: termType = p.Term_TYPEOF case infoKind: termType = p.Term_INFO case keysKind: termType = p.Term_KEYS case getKind: termType = p.Term_GET case equalityKind: termType = p.Term_EQ case inequalityKind: termType = p.Term_NE case lessThanKind: termType = p.Term_LT case lessThanOrEqualKind: termType = p.Term_LE case greaterThanKind: termType = p.Term_GT case greaterThanOrEqualKind: termType = p.Term_GE case logicalNotKind: termType = p.Term_NOT case addKind: termType = p.Term_ADD case subtractKind: termType = p.Term_SUB case multiplyKind: termType = p.Term_MUL case divideKind: termType = p.Term_DIV case moduloKind: termType = p.Term_MOD case appendKind: termType = p.Term_APPEND case prependKind: termType = p.Term_PREPEND case insertAtKind: termType = p.Term_INSERT_AT case spliceAtKind: termType = p.Term_SPLICE_AT case deleteAtKind: termType = p.Term_DELETE_AT case changeAtKind: termType = p.Term_CHANGE_AT case differenceKind: termType = p.Term_DIFFERENCE case indexesOfKind: termType = p.Term_INDEXES_OF case isEmptyKind: termType = p.Term_IS_EMPTY case setInsertKind: termType = p.Term_SET_INSERT case setUnionKind: termType = p.Term_SET_UNION case setDifferenceKind: termType = p.Term_SET_DIFFERENCE case setIntersectionKind: termType = p.Term_SET_INTERSECTION case containsKind: termType = p.Term_CONTAINS case sliceKind: termType = p.Term_SLICE case skipKind: termType = p.Term_SKIP case limitKind: termType = p.Term_LIMIT case sampleKind: termType = p.Term_SAMPLE case matchKind: termType = p.Term_MATCH case getFieldKind: termType = p.Term_GET_FIELD case hasFieldsKind: termType = p.Term_HAS_FIELDS case withFieldsKind: termType = p.Term_WITH_FIELDS case pluckKind: termType = p.Term_PLUCK case withoutKind: termType = p.Term_WITHOUT case mergeKind: termType = p.Term_MERGE case indexCreateKind: termType = p.Term_INDEX_CREATE case indexListKind: termType = p.Term_INDEX_LIST case indexDropKind: termType = p.Term_INDEX_DROP case funcallKind: termType = p.Term_FUNCALL case branchKind: termType = p.Term_BRANCH case anyKind: termType = p.Term_ANY case allKind: termType = p.Term_ALL case forEachKind: termType = p.Term_FOREACH case databaseCreateKind: termType = p.Term_DB_CREATE case databaseDropKind: termType = p.Term_DB_DROP case databaseListKind: termType = p.Term_DB_LIST case errorKind: termType = p.Term_ERROR case implicitVariableKind: termType = p.Term_IMPLICIT_VAR case databaseKind: termType = p.Term_DB case variableKind: termType = p.Term_VAR case ascendingKind: termType = p.Term_ASC case descendingKind: termType = p.Term_DESC case defaultKind: termType = p.Term_DEFAULT default: panic("invalid term kind") } args := []*p.Term{} for _, arg := range arguments { args = append(args, ctx.toTerm(arg)) } var optargs []*p.Term_AssocPair for key, value := range options { optarg := &p.Term_AssocPair{ Key: proto.String(key), Val: ctx.toTerm(value), } optargs = append(optargs, optarg) } return &p.Term{ Type: termType.Enum(), Args: args, Optargs: optargs, } }
// toTerm converts an arbitrary object to a Term, within the context that toTerm // was called on. func (ctx context) toTerm(o interface{}) *p.Term { e := Expr(o) var termType p.Term_TermType arguments := e.args options := map[string]interface{}{} switch e.kind { case literalKind: return ctx.literalToTerm(e.args[0]) case variableKind: termType = p.Term_VAR case javascriptKind: termType = p.Term_JAVASCRIPT case errorKind: termType = p.Term_ERROR case implicitVariableKind: termType = p.Term_IMPLICIT_VAR case databaseKind: termType = p.Term_DB case tableKind: termType = p.Term_TABLE // first arg to table must be the database if len(arguments) == 1 { dbExpr := naryOperator(databaseKind, ctx.databaseName) arguments = []interface{}{dbExpr, arguments[0]} } options["use_outdated"] = ctx.useOutdated case getKind: termType = p.Term_GET case equalityKind: termType = p.Term_EQ case inequalityKind: termType = p.Term_NE case lessThanKind: termType = p.Term_LT case lessThanOrEqualKind: termType = p.Term_LE case greaterThanKind: termType = p.Term_GT case greaterThanOrEqualKind: termType = p.Term_GE case logicalNotKind: termType = p.Term_NOT case addKind: termType = p.Term_ADD case subtractKind: termType = p.Term_SUB case multiplyKind: termType = p.Term_MUL case divideKind: termType = p.Term_DIV case moduloKind: termType = p.Term_MOD case appendKind: termType = p.Term_APPEND case sliceKind: termType = p.Term_SLICE case skipKind: termType = p.Term_SKIP case limitKind: termType = p.Term_LIMIT case getAttributeKind: termType = p.Term_GETATTR case containsKind: termType = p.Term_CONTAINS case pluckKind: termType = p.Term_PLUCK case withoutKind: termType = p.Term_WITHOUT case mergeKind: termType = p.Term_MERGE case betweenKind: termType = p.Term_BETWEEN options["left_bound"] = arguments[1] options["right_bound"] = arguments[2] arguments = arguments[:1] case reduceKind: termType = p.Term_REDUCE options["base"] = arguments[2] arguments = arguments[:2] case mapKind: termType = p.Term_MAP case filterKind: termType = p.Term_FILTER case concatMapKind: termType = p.Term_CONCATMAP case orderByKind: termType = p.Term_ORDERBY case distinctKind: termType = p.Term_DISTINCT case countKind: termType = p.Term_COUNT case unionKind: termType = p.Term_UNION case nthKind: termType = p.Term_NTH case groupedMapReduceKind: termType = p.Term_GROUPED_MAP_REDUCE options["base"] = arguments[4] arguments = arguments[:4] case groupByKind: termType = p.Term_GROUPBY case innerJoinKind: termType = p.Term_INNER_JOIN case outerJoinKind: termType = p.Term_OUTER_JOIN case eqJoinKind: termType = p.Term_EQ_JOIN case zipKind: termType = p.Term_ZIP case coerceToKind: termType = p.Term_COERCE_TO case typeOfKind: termType = p.Term_TYPEOF case updateKind: termType = p.Term_UPDATE options["non_atomic"] = !ctx.atomic case deleteKind: termType = p.Term_DELETE case replaceKind: termType = p.Term_REPLACE options["non_atomic"] = !ctx.atomic case insertKind: termType = p.Term_INSERT options["upsert"] = ctx.overwrite case databaseCreateKind: termType = p.Term_DB_CREATE case databaseDropKind: termType = p.Term_DB_DROP case databaseListKind: termType = p.Term_DB_LIST case tableCreateKind: termType = p.Term_TABLE_CREATE // last argument is the table spec spec := arguments[len(arguments)-1].(TableSpec) arguments = arguments[:len(arguments)-1] if len(arguments) == 0 { // just spec, need to add database dbExpr := naryOperator(databaseKind, ctx.databaseName) arguments = append(arguments, dbExpr) } arguments = append(arguments, spec.Name) if spec.Datacenter != "" { options["datacenter"] = spec.Datacenter } if spec.PrimaryKey != "" { options["primary_key"] = spec.PrimaryKey } if spec.CacheSize != 0 { options["cache_size"] = spec.CacheSize } case tableDropKind: termType = p.Term_TABLE_DROP if len(arguments) == 1 { // no database specified, use the session database dbExpr := naryOperator(databaseKind, ctx.databaseName) arguments = []interface{}{dbExpr, arguments[0]} } case tableListKind: termType = p.Term_TABLE_LIST if len(arguments) == 0 { // no database specified, use the session database dbExpr := naryOperator(databaseKind, ctx.databaseName) arguments = append(arguments, dbExpr) } case funcallKind: termType = p.Term_FUNCALL case branchKind: termType = p.Term_BRANCH case anyKind: termType = p.Term_ANY case allKind: termType = p.Term_ALL case forEachKind: termType = p.Term_FOREACH case funcKind: return ctx.toFuncTerm(arguments[0], arguments[1].(int)) case ascendingKind: termType = p.Term_ASC case descendingKind: termType = p.Term_DESC // special made-up kind to set options on the query case upsertKind: ctx.overwrite = e.args[1].(bool) return ctx.toTerm(e.args[0]) case atomicKind: ctx.atomic = e.args[1].(bool) return ctx.toTerm(e.args[0]) case useOutdatedKind: ctx.useOutdated = e.args[1].(bool) return ctx.toTerm(e.args[0]) default: panic("invalid term kind") } args := []*p.Term{} for _, arg := range arguments { args = append(args, ctx.toTerm(arg)) } var optargs []*p.Term_AssocPair for key, value := range options { optarg := &p.Term_AssocPair{ Key: proto.String(key), Val: ctx.toTerm(value), } optargs = append(optargs, optarg) } return &p.Term{ Type: termType.Enum(), Args: args, Optargs: optargs, } }