def run_gpudb( argv ): """An interface to GPUDB. Run the specified query on GPUDB on the local machine or at the specified address. Also provide usage information. """ # Default values file_name = "" # Add arguments to the parser parser = argparse.ArgumentParser() parser.add_argument( '-g', nargs = '?', default = "127.0.0.1:9191", help = "IP address and port of GPUdb in the format: xxx.xx.xx.xx:xxxx (defaults to 127.0.0.1:9191)" ) parser.add_argument( '--request-path', nargs = '?', default = gpudb_obj_defs_path, help = "Path of the JSON defintions (defaults to %s)" % gpudb_obj_defs_path ) # User must provide one or the other query_group = parser.add_mutually_exclusive_group( required = True ) query_group.add_argument( "--list-queries", action = 'store_true', help = "Lists all available GPUDB queries." ) query_group.add_argument( '--query', nargs = argparse.REMAINDER, help = "Name of the query to be executed and any parameters associated with the query. For example, '--query max_min --attribute x --set_id set1'. Not providing any parameter after the query name will print query specific help information." ) # Print the help message and quit if no arguments are given if ( len(sys.argv) == 1 ): # None provided parser.print_help() sys.exit( 2 ) # Parse the command line arguments args = parser.parse_args() # Parse and check the request JSON path request_path = args.request_path if not os.path.exists( request_path ): # Check that the path exists print "Path for JSONs does not exist: ", request_path sys.exit( 2 ) if request_path[-1] != "/": # simplify logic below by enforcing trailing '/' request_path += "/" # Create a list of all request JSON filenames filenames = [request_path + f for f in os.listdir( request_path ) if "_request.json" in f] # -------------------------------------- # List all endpoint/query names, if desired by user if (args.list_queries == True) or (len(args.query) == 0): # Strip filename of the path and suffix if it's a request JSON file query_names = [ f.replace( request_path, "" ).replace( "_request.json", "" ) for f in filenames if "_request.json" in f ] for q in sorted( query_names ): print q sys.exit( 0 ) # Succesful termination after printing the desired help message # -------------------------------------- # -------------------------------------- # Set up GPUdb GPUdb_IP, GPUdb_Port = args.g.split( ":" ) gpudbdb = GPUdb( encoding = 'BINARY', host = GPUdb_IP, port = GPUdb_Port ) # Find and read the desired query JSON file query_name = args.query[ 0 ] for f in filenames: file_name = f if ("/" + query_name + "_request.json") in f else file_name if file_name == "": print "Query not found: ", query_name sys.exit( 2 ) json_file = open( file_name, "r" ) request_json = json_file.read() json_file.close() # Parse the request JSON to get the parameters request_schema = schema.parse( request_json ) request_json = request_schema.to_json()["fields"] # Create a dictionary of (param name, param type) pairs based on the JSON param_name_type = {} param_vals = {} # param_vals = collections.OrderedDict() for param in request_json: param_name_type[ param['name'] ] = param['type'] # Binary/bytes parameters will be skipped if param['type'] == "string" or param['type'] == "bytes": param_vals[ param['name'] ] = "" # Default is empty string if param['type'] == "map": param_vals[ param['name'] ] = {} # Default is empty map if param['type'] == "list": param_vals[ param['name'] ] = [] # Default is empty list # Note that numeric attributes are not getting a default # User MUST provide such values, or we output an error # Create a parser for query-specific parameters query_parser = argparse.ArgumentParser() # Add parameters to be parsed query_parser.add_argument( "--format-response", action = 'store_true', dest = "format_response", help = "Boolean parameter, include to print formatted GPUDB response. Omitting it prints the raw GPUDB response." ) for pname, ptype in param_name_type.iteritems(): if ptype == "string": # Make string arguments optional query_parser.add_argument( "--" + pname, nargs='?', default="", help = "Defaults to empty string" ) elif ptype == "double" or ptype == "float": query_parser.add_argument( "--" + pname, type = float, required = True, help = "Required parameter, type %s" % ptype ) elif ptype == "long": query_parser.add_argument( "--" + pname, type = long, required = True, help = "Required parameter, type %s" % ptype ) elif ptype == "int": query_parser.add_argument( "--" + pname, type = int, required = True, help = "Required parameter, type %s" % ptype ) elif ptype == "bytes": continue # ignore bytes elif ptype == "boolean": # Boolean flag # User must provide one or the other bool_group = query_parser.add_mutually_exclusive_group( required = True ) bool_group.add_argument( "--" + pname, action = 'store_true', dest = pname, help = "Boolean parameter, include to set %s to TRUE" %pname ) bool_group.add_argument( "--no-" + pname, action = 'store_false', dest = pname, help = "Boolean parameter, include to set %s to FALSE" % pname ) else: # Maps and lists get empty ones by default; handling is delicate; ignore 'bytes' if ptype[ 'type' ] == "map": query_parser.add_argument( "--" + pname, nargs = '?', type = json.loads, default = {}, help = "Expected map value of type: %s; surround the whole map with single quotes (') and any string (key or value) within with double quotes (\"). E.g. for random, --param_map '{\"x\":{\"min\":2}}'. When omitted, defaults to empty map" % ptype['values'] ) else: # Arrays query_parser.add_argument( "--" + pname, type = json.loads, default=[], help = "Comma separated list (escape spaces with \) enclosed in []. For example, for filter_by_nai, --x_vector [1,2,3,4] or --x_vector [1,\ 2,\ 3,\ 4]. If contains strings, then enclose the whole thing within single quotes and the individual string in double quotes. E.g., for filter_by_string, --attributes '[\"x\",\"y\"]'. When omitted, defaults to an empty list." ) # Print the help message and quit if no arguments are given (and none is expected) if ( len( args.query[1:] ) == 0 and len( param_name_type ) > 0 ): print "No parameters provided for query: ", query_name query_parser.print_help() sys.exit( 2 ) # Parse the parameters and store in a dictionary query_args = vars( query_parser.parse_args( args.query[1:] ) ) # Copy the parsed values to the ordered dictionar to pass to GPUdb for key, val in query_args.iteritems(): param_vals[ key ] = val # -------------------------------------- # -------------------------------------- # Call the GPUDB query: # Derive the endpoint name from the query name endpoint_name = "/" + query_name.replace( "_", "" ) # One exception is /add if endpoint_name == "/addobject": endpoint_name = "/add" # Parse request and response schemas for GPUDB (req_schema, resp_schema) = gpudbdb.get_schemas( query_name ) # Perform the GPUDB query response = gpudbdb.post_then_get( req_schema, resp_schema, param_vals, endpoint_name ) print print "GPUDB Response:" if query_args[ "format_response" ] == True: print format_response( response ) else: print response