protected function parseConfig(AnnotationBag $propertyAnnotations) {
		$this->config = [];
		
		//mapping type expression
		if (isset($this->type))
			$this->config['map.type'] = $this->type;
		
		//result map
		if ($propertyAnnotations->has('ResultMap'))
			$this->config['map.result'] = $propertyAnnotations->get('ResultMap')->getValue();
		
		//cache
		if ($propertyAnnotations->has('Cache')) {
			$this->config['cache.ttl'] = intval($propertyAnnotations->get('Cache')->getArgument());
			$this->config['cache.key'] = $propertyAnnotations->get('Cache')->getValue();
		}
		
		//custom options
		$options = $propertyAnnotations->find('Option', Filter::HAS_ARGUMENT);
		
		foreach ($options as $option)
			$this->config[$option->getArgument()] = $option->getValue();
		
		//cacheable
		if ($propertyAnnotations->has('Cacheable')) {
			//check type before assuming is cacheable
			$this->cacheable = !empty($this->type) && !preg_match('/^[arr|array|obj|object]:/', $this->type);
		}
		
		//get evaluation condition
		if ($propertyAnnotations->has('If')) {
			$this->program = new DynamicSQLProgram($propertyAnnotations->get('If')->getValue());
			$this->condition = function ($row, $config) {
				return (bool) $this->program->execute($this->buildEnvironment($config), $row);
			};
		}
		elseif ($propertyAnnotations->has('IfNot')) {
			$this->program = new DynamicSQLProgram($propertyAnnotations->get('IfNot')->getValue());
			$this->condition = function ($row, $config) {
				return !(bool) $this->program->execute($this->buildEnvironment($config), $row);
			};
		}
		elseif ($propertyAnnotations->has('IfNotNull')) {
			$attribute = $propertyAnnotations->get('IfNotNull')->getArgument();
			$this->condition = function($row, $_) use ($attribute) {
				$argument = ArgumentWrapper::wrap($row);
				return !($argument->offsetExists($attribute) && $argument->offsetGet($attribute) === null);
			};
		}
	}