# vim: ft=zsh noet ts=4 sts=4 sw=4

#
# confz functions for PostgreSQL
#

config-protect-mv() {
	local n dst base
	if [[ -d $2 ]]; then
		dst=${2%/}/$1:t
	else
		dst=$2
	fi

	if ! [[ -e $dst ]]; then
		confz_do mv "$1" "$dst"
		return $?
	fi

	n=0
	base=$dst:t
	dst="$dst:h/$(printf "._cfg%04d_%s" $n $base)"

	while [[ -e $dst ]]; do
		n=$[ $n + 1 ]
		dst="$dst:h/$(printf "._cfg%04d_%s" $n $base)"
		(( $n > 9999 )) && die "can not config-protect $dst:t/$base"
	done

	confz_do mv "$1" "$dst"
}

confz_postgresql_cluster_check() {
	checkvars data_dir
	defvar owner postgres
	defvar pgdata $vars[data_dir]
	defvar locale en_US.UTF-8
	defvar initdb initdb
	defvar initdb_opts ''

	[[ -d $vars[data_dir]/base && -e $vars[pgdata]/postgresql.conf ]]
}

confz_postgresql_cluster_do() {
	confz_do mkdir -p $vars[data_dir] $vars[pgdata] || return $?
	confz_do chown -Rf $vars[owner]: $vars[data_dir] || return $?
	confz_do chmod 0700 $vars[data_dir] || return $?
	confz_do su $vars[owner] -c "$vars[initdb] --locale=${(qqq)vars[locale]} --pgdata=${(qqq)vars[data_dir]} $vars[initdb_opts]" || return $?

	local cfg

	if !  [[ $vars[data_dir] == $vars[pgdata] ]]; then
		for cfg in $vars[data_dir]/*.conf(N); do
			confz_do config-protect-mv $cfg $vars[pgdata]/
		done
	fi

	return 0
}

confz_postgresql_cluster_slot_check() {
	checkvars slot
	require postgresql_cluster \?owner \?locale \?initdb_opts \
		pgdata="/etc/postgresql-$vars[slot]/" \
		data_dir="/var/lib/postgresql/$vars[slot]/data" \
		initdb="/usr/lib/postgresql-$vars[slot]/bin/initdb"
}


confz_postgresql_user_check() {
	checkvars name
	defvar user postgres
	defvar psql psql
	defvar createuser createuser
	defvar allow_createdb 0
	defvar allow_createrole 0
	defvar allow_replication 0
	defvar allow_login 1
	defvar superuser 0

	local -a opts

	opts+=( -U $vars[user] )
	(($+vars[host])) && opts+=( --host=$vars[host] )
	(($+vars[port])) && opts+=( --port=$vars[port] )

	do_command=( $vars[createuser] $opts $vars[name] )

	local flag
	for flag in allow_createdb allow_createrole allow_replication allow_login superuser; do
		if (($vars[$flag])); then
			do_command+=( --${flag#allow_} )
		else
			do_command+=( --no-${flag#allow_} )
		fi
	done

	out=$( confz_do $vars[psql] $opts -AP tuples_only=on -c '\dg' template1 ) || \
		die "psql failed"
	grep -q "^$vars[name]|" <<<$out
}

confz_postgresql_db_check() {
	checkvars db owner
	defvar user postgres
	defvar psql psql
	defvar createdb createdb

	local -a opts

	opts+=( -U $vars[user] )
	(($+vars[host])) && opts+=( --host=$vars[host] )
	(($+vars[port])) && opts+=( --port=$vars[port] )

	do_command=( $vars[createdb] $opts $vars[db] -O $vars[owner] )
	if (($+vars[encoding])); then
		do_command+=( -E $vars[encoding] )
	fi

	local out name owner encoding rest
	out=$( confz_do $vars[psql] $opts -lAP tuples_only=on template1 ) || \
		die "psql failed"
	while IFS='|' read name owner encoding rest; do
		if [[ $name == $vars[db] ]]; then
			[[ $owner == $vars[owner] ]] || \
				die "database $name has owner $owner, want $vars[owner]"
			if (($+vars[encoding])); then
				[[ $encoding == $vars[encoding] ]] || \
					die "database $name has encoding $encoding, want $vars[encoding]"
			fi
			return 0
		fi
	done <<<$out

	fail_reason="database ${(qqq)vars[db]} was not found"
	return 1
}

confz_postgresql_schema_check() {
	checkvars db owner schema_name
	defvar user postgres
	defvar psql psql

	local -a opts

	opts+=( -U $vars[user] )
	(($+vars[host])) && opts+=( --host=$vars[host] )
	(($+vars[port])) && opts+=( --port=$vars[port] )

	do_command=(
		$vars[psql] $opts $vars[db] -1
		-c "CREATE SCHEMA $vars[schema_name]; ALTER SCHEMA $vars[schema_name] OWNER TO $vars[owner]"
	)

	local out schema owner
	out=$( confz_do $vars[psql] $opts -AP tuples_only=on -c '\dn' $vars[db] ) || die "psql failed"
	while IFS='|' read schema owner; do
		if [[ $schema == $vars[schema_name] ]]; then
			[[ $owner == $vars[owner] ]] || \
				die "schema $schema has owner $owner, want $vars[owner]"
			return 0
		fi
	done <<<$out

	fail_reason="schema ${(qqq)vars[schema_name]} was not found in database ${(qqq)vars[db]}"
	return 1
}

confz_postgresql_extension_check() {
	checkvars db extension schema_name
	defvar user postgres
	defvar psql psql

	local -a opts

	opts+=( -U $vars[user] )
	(($+vars[host])) && opts+=( --host=$vars[host] )
	(($+vars[port])) && opts+=( --port=$vars[port] )

	do_command=(
		$vars[psql] $opts $vars[db] -1
		-c "CREATE EXTENSION $vars[extension] SCHEMA $vars[schema_name]"
	)

	local out extension version schema comment
	out=$( confz_do $vars[psql] $opts -AP tuples_only=on -c '\dx' $vars[db] ) || die "psql failed"
	while IFS='|' read extension version schema comment; do
		if [[ $extension == $vars[extension] ]]; then
			[[ $schema == $vars[schema_name] ]] || \
				die "extension $extension has schema $schema, want $vars[schema_name]"
			return 0
		fi
	done <<<$out

	fail_reason="extension ${(qqq)vars[extension]} was not found in database ${(qqq)vars[db]}"
	return 1
}

confz_postgresql_content_check() {
	checkvars db schema psql_input
	defvar user postgres
	defvar psql psql

	local out
	local -a opts

	opts+=( -U $vars[user] )
	(($+vars[host])) && opts+=( --host=$vars[host] )
	(($+vars[port])) && opts+=( --port=$vars[port] )

	out=$( confz_do $vars[psql] $opts -AP tuples_only=on -c '\d' $vars[db] ) || die "psql failed"
	if [[ -z $out || $out == 'No relations found.' ]]; then
		fail_reason="the schema for ${(qqq)vars[db]} is empty"
		return 1
	elif [[ $out != $vars[schema] ]]; then
		die "the schema for ${(qqq)vars[db]} differs:"$'\n'"$( \
			diff -u <(print -r - $vars[schema]) <(print -r - $out) )"
	fi
	return 0
}

confz_postgresql_content_do() {
	local -a opts

	opts+=( -U $vars[user] )
	(($+vars[host])) && opts+=( --host=$vars[host] )
	(($+vars[port])) && opts+=( --port=$vars[port] )

	confz_do $vars[psql] $opts -1 $vars[db] -f - <<<$vars[psql_input]
}