コード例 #1
0
	def __init__( self ):
		self._data = PersistencyManager()
		self._mods = []
		self.lastGeneratedId = {}
コード例 #2
0
class PersistencyInterface( object ):
	def __init__( self ):
		self._data = PersistencyManager()
		self._mods = []
		self.lastGeneratedId = {}



	def query(self, wip):
		try:
			if wip == 'MODS':
				tmp = self._mods
				self._mods = []
				return tmp
			return self._query(wip, wip)
		# except EntityError as e:
		# 	print 'Error in method\n\tQuery: ' + wip + '\n\tMethod: ' + e.method + '\n\tMessage: ' + e.msg
		# 	raise DataLayerError('Error in the DataLayer. Query: ' + wip)
		# except ModelError as e:
		# 	print 'Error in method\n\tQuery: ' + wip + '\n\tMethod: ' + e.method + '\n\tMessage: ' + e.msg
		# 	raise DataLayerError('Error in the DataLayer. Query: ' + wip)
		except KeyError:
			print 'Unknown KeyError'
			raise DataLayerError('Error in the DataLayer. Query: ' + wip)
		except:
			print 'Unknown OtherError'
			print '-'*60
			traceback.print_exc(file=sys.stdout)
			print '-'*60
			e = 'DataLayer: Unknown error'
			raise DataLayerError('Error in the DataLayer. Query: ' + wip)


	def _query(self, wip, original):
		# print '--> %s -> %s' % (original.__repr__(), wip.__repr__(), )
		resp = []
		
		# Handling of multiple commands
		# example: '<expr>.&.<expr>'
		wip = wip.split('.&.')
		if len(wip)>1:
			resp = [self._query(x, original) for x in wip]
			resp = [x for x in resp if x != None]
			return resp
		wip = wip[0]
		
		# Handling request for schemas names
		# example: ''
		# return [schema names]
		if len(wip) == 0:
			return self._data.getInfo()
		
		# Handling insertion of new schema
		# example '+.fileName'
		if len(wip) and wip[0] == '+':
			self._data.addModel(wip[2:])
			self._mods.append(wip)
			return

		# Handling removal of existing schema
		# example '-.modelName'
		if len(wip) and wip[0] == '-':
			self._data.removeModel(wip[2:])
			self._mods.append(wip)
			return
		
		# Handling ids requests
		# example '!.abc.ecology'
		if len(wip) and wip[0] == '!':
			return self.lastGeneratedId[wip[2:]]

		# Handling subscription
		#    resending query with no subscribtion token
		if Q_SUBSCRIBE in wip:
			return self._query(wip[len(Q_SUBSCRIBE):], original)
		
		# Handling basic commands
		else:
			data = wip.split('.')
			
			# Return if some issues arose in the computations
			# Need to return None for the '.&.' to work
			if 'None' in data:
				return None
			
			self._checkConsistency( data )
			expansion = self._getExpansionArray(data)
			
			# Branch executed if query contains intra queries
			if True in expansion:
				idx = expansion.index(True)
				before = '.'.join( data[:idx] )
				after = '.'.join( data[idx+1:] )
				if len(before):
					before += '.'
				if len(after):
					after = '.'+ after
				# example: '<expr1>[]<expr>'
				# becomes: '<expr1>[eval(expr1)]<expr>'
				if data[idx] == '[]':
					expanded = self._query( before[:-1], wip )
					# if original[0] == '#' and exapnded == '[]':
					#     exapnded = None
					return self._query(  before + str(expanded) + after, original )
				else:
					# just to be faster ... check the case of concrete inner query to avoid the try ... except and eval ...
					# same as except branch
					if '.' in data[idx]:
						if ']:[' in data[idx]:
							tokens = data[idx][1:-1].split(':')
							expanded = ''
							for tok in tokens:
								if tok[-1] == ']': tok = tok[:-1]
								if tok[0] == '[': tok = tok[1:]
								tmp = self._query(tok, wip)
								if isinstance(tmp,list):
									# print '<><>' +str(tmp)
									tmp = tmp[0]
								expanded += str(tmp)
								expanded += ':'
							return self._query( before + str(expanded[:-1]) + after, original )
						expanded = self._query( data[idx][1:-1], wip )
						# if not len(expanded):
						# 	return expanded
						return self._query(  before + str(expanded) + after, original )
					try:
						# example: '<expr>[id1, ... ,idN]<expr>'
						# becomes: '<expr>.id1.<expr>.&. ... .&.<expr>.idN.<expr>' <-- Handled by the previous if
						# in case of strange errors during debug uncomment the following line 
						# wip = long(data[idx][1:-1].split(',')[0])
						wip = eval(data[idx])
						if not isinstance(wip, list):
							raise
						return self._query( '.&.'.join( before + str(x) + after for x in wip), original )
					except:
						# example: '<expr>[<expr1>]<expr>'
						# becomes: '<expr>[eval(expr1)]<expr>'
						expanded = self._query( data[idx][1:-1], wip )
						# if not len(expanded):
						# 	return expanded
						return self._query(  before + str(expanded) + after, original )
			else:
				# In case no expansions need to be evaluated, terminate the evaluation of the query in the case of a subscribtion
				if Q_SUBSCRIBE in original:
					return wip

			# Handle request of entities name
			# example: 'abc'
			# return [entity names]
			if len(data) == 1:
				return self._data.getInfo(data[0])

			# Handle request of ids present for an entity
			# example: 'abc.activity'
			# return [ids]
			if len(data) == 2:
				return self._data.getInfo(data[0], data[1])

			# Handle request of fields/relations names or the insertion of a new entity entry
			# example: 'abc.activity.123' or 'abc.activity.+'
			# return [fields + refs] or id 
			if len(data) == 3:
				if data[2] == '+':
					self._mods.append(wip)
					currId = self._data.add(data[0], data[1])
					self.lastGeneratedId[data[0]+'.'+data[1]] = currId
					return currId
				else:
					return self._data.getInfo(data[0], data[1], long(data[2]))

			# Handle the request of a concrete field/relation or the removal of an entity entry
			# example: 'abc.activity.123.name' or 'abc.activity.123.user' or 'abc.activity.-.123'
			# return val or return [ids] or nothing
			if len(data) == 4:
				if data[2] == '-':
					self._data.remove(data[0], data[1], long(data[3]))
					self._mods.append(wip)
					return
				return self._data.getInfo(data[0], data[1], long(data[2]), data[3])

			# Handle the request for field info
			# example: 'abc.activity.123.name.?'
			# return val or return [field info]
			if len(data) == 5:
				return self._data.getFieldInfo(data[0], data[1], long(data[2]), data[3])
			

			# Handle the assignment of a value to a field or the insertion/removal of a relation as well as the comparison of a value
			# example: 'abc.activity.123.name.=.val' or 'abc.activity.123.user.+.val' or
			#          'abc.activity.123.user.-.val' or' abc.application_state.[].user.==.val'
			# no return 
			if len(data) == 6:
				if data[4] == '=':
					self._data.update(data[0], data[1], long(data[2]), data[3], self._cleanValue(data[5]))
					self._mods.append(wip)
				elif data[4] == '+':
					self._data.ref(data[0], data[1], long(data[2]), data[3], long(data[5]))
					self._mods.append(wip)
				elif data[4] == '-':
					self._data.deref(data[0], data[1], long(data[2]), data[3], long(data[5]))
					self._mods.append(wip)
				# TODO > Check == is it a comparison?
				elif data[4] == '==':
					try:
						wip = self._data.get(data[0], data[1], long(data[2]), data[3]) 
					# TODO > CHECK might be a problem
					except EntityError:
						return None
					except ModelError:
						return None
					resp = False
					tmp = self._cleanValue(data[5])
					try:
						tmp = long(tmp)
						wip = long(wip)
					except:
						pass
					if isinstance(wip, list):
						resp = tmp in wip
					else:
						resp = wip == tmp
					return long(data[2]) if resp else None
				elif data[4] == '~=':
					# >>> a = ['12345:67812345:678','123454:67812345:678','12345:67812345:000']
					# >>> check = '(12345):[0-9]*:[0-9]*'
					# >>> list( x.group() for x in list( re.search(check,y) for y in a ) if x != None )
					# ['12345:67812345:678', '12345:67812345:000']
					# abc.ecology.[].name.~=.{{(12345):[0-9]*:[0-9]*}}
					regexp = self._cleanValue(data[5])
					# check = self._data.get(data[0], data[1], long(data[2]), data[3])
					check = self._query( '.'.join(data[:4]), original )
					ret = check if re.search(regexp,check) else None
					return ret if not ret else self._query( '.'.join(data[:4]) + '.==.' + ret, original )
				return



	# Method to remove delimiters, default: value delimiter
	def _cleanValue(self, val, delimiter=Q_VALUE_DELIMITER):
		tmp = val
		if tmp in Q_PLACE_HOLDERS:
			print '>> changing' + val + ' - ' + Q_PLACE_HOLDERS[0]
			if tmp == Q_PLACE_HOLDERS[0]:
				return str(DT.now())
		if delimiter[0] in tmp:
			tmp = tmp[len(delimiter[0]):]
		if delimiter[1] in tmp:
			tmp = tmp[:-len(delimiter[1])]
		return tmp



	# Method to control parenthesis and value delimiter consistency 
	def _checkConsistency(self, data):
		toCheck = [Q_EXPANSION_DELIMITER, Q_VALUE_DELIMITER]
		currentIdx = 0
		
		while currentIdx < len(toCheck):
			modified = False
			delim = toCheck[currentIdx]
			#expA = [ len(x)>=len(delim[0]) and x[0:len(delim[0])]==delim[0] for x in data]
			#expB = [ len(x)>=len(delim[1]) and x[-len(delim[1]):]==delim[1]  for x in data]
			r = []
			for x in data:
				r.append(0)
				if len(x)<len(delim[0]):
					continue
				while r[-1]<len(data[len(r)-1]) and data[len(r)-1][r[-1]:r[-1]+len(delim[0])] == delim[0]:
					r[-1] += 1
			expA = r
			r = []
			for x in data:
				r.append(0)
				if len(x)<len(delim[1]):
					continue
				while r[-1]<len(data[len(r)-1]):
					check = False
					if not r[-1]:
						check = data[len(r)-1][-(len(delim[1])+r[-1]):] == delim[1]
					else:
						check = data[len(r)-1][-(len(delim[1])+r[-1]):-(r[-1])] == delim[1]
					if not check:
						break
					r[-1] += 1
			expB = r			

			idx = 0
			other = 0

			for i, x in enumerate(expA):
				other += expA[i]
				other -= expB[i]
				if expA[i]!=expB[i]:
					idx = i
					break
			# print expA
			# print expB
			# print other
			# print data
			if idx and other > 0:
				modified = True
				while other:
					data[i] += '.'+data[i+1]
					del data[i+1]
					idx += 1
					other += expA[idx]
					other -= expB[idx]

			if not modified:
				currentIdx += 1


	# Returns a machine readable representation of the query with information about the possible inter queries
	def _getExpansionArray(self, data):
		return [ x[0]==Q_EXPANSION_DELIMITER[0] and x[-1]==Q_EXPANSION_DELIMITER[1] for x in data]