def execute(self, script, params={}, isolate=True, transaction=True, pretty=False): """ executes the given gremlin script with the provided parameters :param script: the gremlin script to isolate :type script: string :param params: the parameters to execute the script with :type params: dictionary :param isolate: wraps the script in a closure so any variables set aren't persisted for the next execute call :type isolate: bool :param transaction: query will be wrapped in a transaction if set to True (default) :type transaction: bool :param pretty: will dedent the script if set to True :type pretty: bool :rtype: list """ self._conn.send_message( messages.ScriptRequest( script=script, params=params, session_key=self._session_key, isolate=isolate, in_transaction=transaction ) ) response = self._conn.get_response() if isinstance(response, messages.ErrorResponse): raise exceptions.RexProScriptException(response.message) return response.results
def open_transaction(self): """ opens a transaction """ if self._in_transaction: raise exceptions.RexProScriptException("transaction is already open") self.execute( script='g.stopTransaction(FAILURE)', isolate=False ) self._in_transaction = True
def _validate_params(self): """ Checks that the parameters are ok (no invalid types, no weird key names) """ for k, v in self.params.items(): if re.findall(r'^[0-9]', k): raise exceptions.RexProScriptException( "parameter names can't begin with a number") if re.findall(r'[\s\.]', k): raise exceptions.RexProException( "parameter names can't contain {}".format( re.findall(r'^[0-9]', k)[0])) if not isinstance( v, (int, long, float, basestring, dict, list, tuple)): raise exceptions.RexProScriptException( "{} is an unsupported type".format(type(v)))
def raise_exception(self): if self.meta == self.INVALID_MESSAGE_ERROR: raise exceptions.RexProInvalidMessageException(self.message) elif self.meta == self.INVALID_SESSION_ERROR: raise exceptions.RexProInvalidSessionException(self.message) elif self.meta == self.SCRIPT_FAILURE_ERROR: raise exceptions.RexProScriptException(self.message) elif self.meta == self.AUTH_FAILURE_ERROR: raise exceptions.RexProAuthenticationFailure(self.message) elif self.meta == self.GRAPH_CONFIG_ERROR: raise exceptions.RexProGraphConfigException(self.message) elif self.meta == self.CHANNEL_CONFIG_ERROR: raise exceptions.RexProChannelConfigException(self.message) elif self.meta == self.RESULT_SERIALIZATION_ERROR: raise exceptions.RexProSerializationException( "Meta: {} ({}), Message: {}, Raw Data: {}".format( self.meta, type(self.meta), self.message, repr(self.data))) else: raise exceptions.RexProScriptException( "Meta: {} ({}), Message: {}, Raw Data: {}".format( self.meta, type(self.meta), self.message, repr(self.data)))
def close_transaction(self, success=True): """ closes an open transaction :param success: indicates which status to close the transaction with, True will commit the changes, False will roll them back :type success: bool """ if not self._in_transaction: raise exceptions.RexProScriptException("transaction is not open") self.execute( script='g.stopTransaction({})'.format('SUCCESS' if success else 'FAILURE'), isolate=False ) self._in_transaction = False
def get_response(self): """ gets the message type and message from rexster Basic Message Structure: reference: https://github.com/tinkerpop/rexster/wiki/RexPro-Messages +---------------------+--------------+---------------------------------------------------------+ | segment | type (bytes) | description | +=====================+==============+=========================================================+ | protocol version | byte (1) | Version of RexPro, should be 1 | +---------------------+--------------+---------------------------------------------------------+ | serializer type | byte (1) | Type of Serializer: msgpack==0, json==1 | +---------------------+--------------+---------------------------------------------------------+ | reserved for future | byte (4) | Reserved for future use. | +---------------------+--------------+---------------------------------------------------------+ | message type | byte (1) | Tye type of message as described in the value columns. | +---------------------+--------------+---------------------------------------------------------+ | message size | int (4) | The length of the message body | +---------------------+--------------+---------------------------------------------------------+ | message body | byte (n) | The body of the message itself. The Good, Bad and Ugly. | +---------------------+--------------+---------------------------------------------------------+ Message Types: +--------------+----------+-------+---------------------------------------------------------------+ | message type | type | value | description | +==============+==========+=======+===============================================================+ | session | request | 1 | A request to open or close the session with the RexPro Server | +--------------+----------+-------+---------------------------------------------------------------+ | session | response | 2 | RexPro server response to session request | +--------------+----------+-------+---------------------------------------------------------------+ | script | request | 3 | A request to process a gremlin script | +--------------+----------+-------+---------------------------------------------------------------+ | script | response | 5 | A response to a script request | +--------------+----------+-------+---------------------------------------------------------------+ | error | response | 0 | A RexPro server error response | +--------------+----------+-------+---------------------------------------------------------------+ :returns: RexProMessage """ msg_version = self.recv(1) if not msg_version: # pragma: no cover # Can only be tested against a known broken version - none known yet. raise exceptions.RexProConnectionException( 'socket connection has been closed') if bytearray(msg_version)[0] != 1: # pragma: no cover # Can only be tested against a known broken version - none known yet. raise exceptions.RexProConnectionException( 'unsupported protocol version: {}'.format(msg_version)) serializer_type = self.recv(1) if bytearray(serializer_type)[0] != 0: # pragma: no cover # Can only be tested against a known broken version - none known yet. raise exceptions.RexProConnectionException( 'unsupported serializer version: {}'.format(serializer_type)) # get padding self.recv(4) msg_type = self.recv(1) msg_type = bytearray(msg_type)[0] msg_len = struct.unpack('!I', self.recv(4))[0] if msg_len == 0: # pragma: no cover # This shouldn't happen unless there is a server-side problem raise exceptions.RexProScriptException( "Insufficient data received") #response = '' #while len(response) < msg_len: # response += self.recv(msg_len) response = bytearray() while msg_len > 0: chunk = self.recv(msg_len) response.extend(chunk) msg_len -= len(chunk) MessageTypes = messages.MessageTypes type_map = { MessageTypes.ERROR: messages.ErrorResponse, MessageTypes.SESSION_RESPONSE: messages.SessionResponse, MessageTypes.SCRIPT_RESPONSE: messages.MsgPackScriptResponse } if msg_type not in type_map: # pragma: no cover # this shouldn't happen unless there is an unknown rexpro version change raise exceptions.RexProConnectionException( "can't deserialize message type {}".format(msg_type)) return type_map[int(msg_type)].deserialize(response)