Ejemplo n.º 1
0
func QueryDB(req *http.Request) interface{} {
	// get a variable ready to hold the incoming query
	var query queryStruct

	// read the incoming html post body and hold it in the query var made above
	decoder := json.NewDecoder(req.Body)

	err := decoder.Decode(&query)
	if err != nil {
		log.Panic(err)
	}

	// what type of query is this, an aggregation or is data being returned?
	switch {
	case len(query.SELECT) == 0 && query.COUNT != "":
		// they want a count!
		return countQuery(query)

	case len(query.SELECT) > 0 && query.COUNT == "":
		// they want some data returned!
		return selectQuery(query)

	default:
		log.Panic(error_.New("Not a valid query! Valid queries must have one of SELECT / COUNT!"))
	}

	// should never get here!
	// NOTE(@adam-hanna): need to implement proper error handling!
	return nil
}
Ejemplo n.º 2
0
func evalWhereClause(mWhere map[string]interface{}) []uint64 {
	// create an array to hold the idx's of all the data that meet our search
	tempKeysMatched := make([][]uint64, 0)

	// loop through the where clause, applying the appropriate logic where necessary
	for key, val := range mWhere {
		switch key {
		case "$OR":
			tempKeysMatched = append(tempKeysMatched, evalOrClause(val.([]interface{})))
		case "$NOT":
			tempKeysMatched = append(tempKeysMatched, evalNotClause(val.(map[string]interface{})))
		case "$NOR":
			tempKeysMatched = append(tempKeysMatched, evalNorClause(val.([]interface{})))

		default:
			// check to see if the values of the keys are anything special
			if testMap(val) {
				// it's a map!
				m := val.(map[string]interface{})

				// it should only have one key!
				for key1, val1 := range m {
					switch key1 {
					case "$IN":
						tempKeysMatched = append(tempKeysMatched, evalInClause(key, val1.([]interface{})))
					case "$NIN":
						tempKeysMatched = append(tempKeysMatched, evalNinClause(key, val1.([]interface{})))

					default:
						// ermm... this should never happen.... I NEED AN ADULT!
						log.Panic(error_.New("Not a valid query! Only $IN and $NIN are valid sub-documents!"))
					}
				}
			} else {
				// not a map!
				// the default is treated as an $AND, so add it to the temp index
				// we will run an intersection on the temp index last.
				// NOTE(@adam-hanna): we only support strings for now!
				tempKeysMatched = append(tempKeysMatched, index.QueryIndex(key, val.(string)))
			}
		}
	}

	// assume that where the user didn't input a logical operator, that an $AND was implied.
	// therefore, run the interesection...
	return arrayOperations.SortedIntersectUint64Arr(tempKeysMatched)
}
Ejemplo n.º 3
0
func selectQuery(query queryStruct) []map[string]interface{} {
	// make an array to hold the return
	var aReturn []map[string]interface{}

	// is a group by present?
	switch query.GROUPBY {
	case "":
		// no groupby present. good. they aren't supported in select queries
		// Loop through the "WHERE" key/vals. No logical operator (i.e. and / or) means "and" (i.e. intersect not union)
		// write the matching keys to our multi-dimensional array
		// NOTE(@adam-hanna): what if a field in the where is an ID or not an indexed field?
		// find the intersection of the idx's
		// NOTE(@adam-hanna): should be doing a check on query object in separate function
		// to be sure it meets specs, rather than doing it here?
		finalKeysMatched := evalWhereClause(query.WHERE)

		// redimension the return array
		aReturn = make([]map[string]interface{}, len(finalKeysMatched))

		// loop through the idx's that match all of our where clauses, pulling the data
		for matchedIdx := range finalKeysMatched {
			// make a map that represents the data to be returned
			// the keys of this map represent the column names, the vals represent the data points
			aReturn[matchedIdx] = make(map[string]interface{})

			// Finally, grab the data that the user has asked to be returned
			// NOTE(@adam-hanna): add support for "*"
			for idx := range query.SELECT {
				aReturn[matchedIdx][query.SELECT[idx]] = data.GetDataPointByIdx(query.SELECT[idx], finalKeysMatched[matchedIdx])
			}
		}

	default:
		// groupby's are not allowed in select queries!
		// NOTE(@adam-hanna): should be doing a check on query object in separate function
		// to be sure it meets specs, rather than doing it here?
		log.Panic(error_.New("Not a valid query! GROUPBY parameters are not allowed in SELECT queries!"))
	}

	return aReturn
}
Ejemplo n.º 4
0
Archivo: cli.go Proyecto: mwatts/PDQdb
func StartCLI(cliFlags *CliFlagsStruct) {
	app := cli.NewApp()
	app.Action = func(ctx *cli.Context) {
		csvConfigFilePath := ctx.GlobalString("config-file-path")
		if csvConfigFilePath == "" {
			log.Fatal(
				error_.New("--config-file-path (or -c) required!"),
			)
		}
		csvFilePath := ctx.GlobalString("file-path")
		if csvFilePath == "" {
			log.Fatal(
				error_.New("--file-path (or -f) required!"),
			)
		}
		serverHostname := ctx.GlobalString("server-hostname")
		serverPort := uint16(ctx.GlobalInt("server-port"))

		// build the cli struct to send back to main
		cliFlags.ConfigFilePath = csvConfigFilePath
		cliFlags.FilePath = csvFilePath
		cliFlags.ServerHostname = serverHostname
		cliFlags.ServerPort = serverPort
	}
	app.Authors = []cli.Author{
		{
			Email: "*****@*****.**",
			Name:  "Adam Hanna",
		},
		{
			Email: "*****@*****.**",
			Name:  "Jonathan Barronville",
		},
	}
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "config-file-path,c",
			Usage: "Path to the JSON config file for the data set.",
		},
		cli.StringFlag{
			Name:  "file-path,f",
			Usage: "Path to the CSV file to load.",
		},
		cli.StringFlag{
			Name:  "server-hostname,n",
			Usage: "Server hostname.",
			Value: "localhost",
		},
		cli.IntFlag{
			Name:  "server-port,p",
			Usage: "Server port.",
			Value: 38216,
		},
	}
	app.Name = "PDQdb"
	app.Usage = "A read-optimized, in-memory, data processing engine."
	app.Version = "0.0.1"
	err := app.Run(os.Args)
	if err != nil {
		log.Fatal(err)
	}
}