/**
 *	Check if a record exists in the cluster via its key.
 *	
 *	@param as			The aerospike instance to use for this operation.
 *	@param err			The as_error to be populated if an error occurs.
 *	@param policy		The policy to use for this operation. If NULL, then the default policy will be used.
 *	@param key			The key of the record.
 *	@param record       The record to populated with metadata if record exists, otherwise NULL
 *
 *	@return AEROSPIKE_OK if successful. Otherwise an error.
 */
as_status aerospike_key_exists(
	aerospike * as, as_error * err, const as_policy_read * policy, 
	const as_key * key, 
	as_record ** rec) 
{
	// we want to reset the error so, we have a clean state
	as_error_reset(err);
	
	// resolve policies
	as_policy_read p;
	as_policy_read_resolve(&p, &as->config.policies, policy);

	uint32_t	timeout = p.timeout == UINT32_MAX ? 0 : p.timeout;
	uint32_t	gen = 0;
	uint32_t	ttl = 0; // TODO - a version of 'exists' that returns all metadata
	int     	nvalues = 0;
	cl_bin *	values = NULL;
	
	cl_rv rc = CITRUSLEAF_OK;

	switch ( p.key ) {
		case AS_POLICY_KEY_DIGEST: {
			as_digest * digest = as_key_digest((as_key *) key);
			rc = citrusleaf_exists_digest(as->cluster, key->ns, (cf_digest *) digest->value,
					values, nvalues, timeout, &gen, &ttl);
			break;
		}
		case AS_POLICY_KEY_SEND: {
			cl_object okey;
			asval_to_clobject((as_val *) key->valuep, &okey);
			as_digest * digest = as_key_digest((as_key *) key);
			rc = citrusleaf_exists_key(as->cluster, key->ns, key->set, &okey, (cf_digest*)digest->value,
					values, nvalues, timeout, &gen, &ttl);
			break;
		}
		default: {
			// ERROR CASE
			break;
		}
	}

	if ( values != NULL ) {
		// We are freeing the bins' objects, as opposed to bins themselves.
		citrusleaf_bins_free(values, nvalues);
		free(values);
	}

	switch(rc) {
		case CITRUSLEAF_OK: 
			{
				as_record * r = *rec;
				if ( r == NULL ) { 
					r = as_record_new(0);
				}   
				r->gen = (uint16_t) gen;
				r->ttl = ttl;
				*rec = r;
				break;
			}

		default:
			*rec = NULL;
			break;
	}

	return as_error_fromrc(err,rc);
}
/**
 *	Check if a record exists in the cluster via its key.
 *	
 *	@param as			The aerospike instance to use for this operation.
 *	@param err			The as_error to be populated if an error occurs.
 *	@param policy		The policy to use for this operation. If NULL, then the default policy will be used.
 *	@param key			The key of the record.
 *	@param exists    	The variable to populate with `true` if the record exists, otherwise `false`.
 *
 *	@return AEROSPIKE_OK if successful. Otherwise an error.
 */
as_status aerospike_key_exists(
	aerospike * as, as_error * err, const as_policy_read * policy, 
	const as_key * key, 
	bool * exists) 
{
	// we want to reset the error so, we have a clean state
	as_error_reset(err);
	
	// resolve policies
	as_policy_read p;
	as_policy_read_resolve(&p, &as->config.policies, policy);

	uint32_t	timeout = p.timeout == UINT32_MAX ? 0 : p.timeout;
	uint32_t	gen = 0;
	uint32_t	ttl = 0; // TODO - a version of 'exists' that returns all metadata
	int     	nvalues = 0;
	cl_bin *	values = NULL;
	
	cl_rv rc = CITRUSLEAF_OK;

	switch ( p.key ) {
		case AS_POLICY_KEY_DIGEST: {
			as_digest * digest = as_key_digest((as_key *) key);
			rc = citrusleaf_exists_digest(as->cluster, key->ns, (cf_digest *) digest->value,
					values, nvalues, timeout, &gen, &ttl);
			break;
		}
		case AS_POLICY_KEY_SEND: {
			cl_object okey;
			asval_to_clobject((as_val *) key->valuep, &okey);
			rc = citrusleaf_exists_key(as->cluster, key->ns, key->set, &okey,
					values, nvalues, timeout, &gen, &ttl);
			break;
		}
		default: {
			// ERROR CASE
			break;
		}
	}

	if ( values != NULL ) {
		free(values);
	}

	switch(rc) {
		case CITRUSLEAF_OK:
			if ( exists ) {
				*exists = true;
			}
			return AEROSPIKE_OK;
		case CITRUSLEAF_FAIL_NOTFOUND:
			if ( exists ) {
				*exists = false;
			}
			return AEROSPIKE_OK;
		default:
			if ( exists ) {
				*exists = false;
			}
			return as_error_fromrc(err,rc);
	}
}