"""
Helpers for dealing with obscore-published tables and its view.
"""

#c Copyright 2008-2024, the GAVO project <gavo@ari.uni-heidelberg.de>
#c
#c This program is free software, covered by the GNU GPL.  See the
#c COPYING file in the source distribution.


import contextlib
import types

from gavo import base
from gavo.rscdef import scripting


@contextlib.contextmanager
def suspendFromObscore(rd, connection):
	"""a context manager to remove everything within rd from obscore in
	the controlled block.

	This is a good idea when doing larger operations in the RD, as a
	singled locked table (e.g., while clustering) in ivoa.obscore will lock the
	whole thing.

	This will commit the connection, once before entering the controlled
	block, and once after, if there actually are obscore-published tables
	in RD.
	"""
	prevClauses = list(connection.queryToDicts(
		"SELECT tablename, sqlfragment, sourcerd FROM ivoa._obscoresources"
		" WHERE sourceRD=%(sourceRD)s",
		{"sourceRD": rd.sourceId}))

	if not prevClauses:
		yield
	
	else:
		updateObscore = scripting.PythonScriptRunner(
			base.resolveCrossId("//obscore#createObscoreView")).run
		fakeTable = types.SimpleNamespace(connection=connection)

		connection.execute("DELETE FROM ivoa._obscoresources"
			" WHERE sourceRD=%(sourceRD)s",
			{"sourceRD": rd.sourceId})
		updateObscore(fakeTable)
		connection.commit()

		try:
			yield
		except:
			connection.rollback()
			raise

		finally:
			with connection.cursor() as c:
				c.executemany("INSERT INTO ivoa._obscoresources"
					" (tablename, sqlfragment, sourcerd)"
					" VALUES (%(tablename)s, %(sqlfragment)s, %(sourcerd)s)",
					prevClauses)
			updateObscore(fakeTable)
			connection.commit()


def restoreObscore(connection):
	"""sees if this system should have an obscore table and re-creates
	it if it's missing.
	"""
	q = base.UnmanagedQuerier(connection)
	if q.getTableType("ivoa._obscoresources") is not None:
		fakeTable = types.SimpleNamespace(connection=connection)
		n = list(q.connection.query(
			"SELECT count(*) from ivoa._obscoresources"))[0][0]
		if n>1: # ivoa.emptyobscore doesn't count
			scripting.PythonScriptRunner(
				base.resolveCrossId("//obscore#createObscoreView")
				).run(fakeTable)

