<resource resdir="__system" schema="dc">
	<meta name="creationDate">2013-07-26T10:00:00</meta>
	<meta name="description">The datalink response structure, and
	the management table for async datalink jobs.  For the STREAMs
	that have been here in previous DaCHS versions, see //soda.
	</meta>
	<meta name="subject">virtual-observatories</meta>

	<table id="dlresponse">
		<meta name="description">Data links for data sets.</meta>
		<column name="ID" type="text"
			ucd="meta.id;meta.main"
			tablehead="PubDID"
			description="Publisher data set id; this is an identifier for
				the dataset in question and can be used to retrieve the data."
			verbLevel="1"/>
		<column name="access_url" type="text"
			ucd="meta.ref.url"
			tablehead="URL"
			description="URL to retrieve the data or access the service."
			verbLevel="1" displayHint="type=url"/>
		<column name="service_def" type="text"
			ucd="meta.code"
			tablehead="Svc. Type"
			description="Identifier for the type of service if accessURL refers
				to a service."
			verbLevel="1"/>
		<column name="error_message" type="text"
			ucd="meta.code.error"
			tablehead="Why not?"
			description="If accessURL is empty, this column gives the reason why."
			verbLevel="20"/>
		<column name="description" type="text"
			ucd="meta.note"
			tablehead="Description"
			description="More information on this link"
			verbLevel="1"/>
		<column name="semantics" type="text"
			ucd="meta.code"
			tablehead="What?"
			description="What kind of data is linked here?  Standard identifiers
				here include science, calibration, preview, info, auxiliary" 
				verbLevel="1"/>
		<column name="content_type" type="text"
			ucd="meta.code.mime"
			tablehead="M. Type"
			description="Media type for the data returned."
			verbLevel="1"/>
		<column name="content_length" type="bigint"
			ucd="phys.size;meta.file" unit="byte"
			tablehead="Size"
			description="Size of the resource at access_url"
			verbLevel="1">
			<values nullLiteral="-1"/>
		</column>
	</table>

	<data id="make_response" auto="False">
		<!-- this data build a datalink response table out of LinkDefs.
		The input parameters for the computational part are built in
		within datalink.getDatalinkDescriptionResource. -->
		<embeddedGrammar>
			<iterator>
				<code>
					for linkDef in self.sourceToken:
						yield linkDef.asDict()
				</code>
			</iterator>
		</embeddedGrammar>
		
		<make table="dlresponse"/>
	</data>

	<!-- ************************************* generic datalink objects -->
	<procDef type="descriptorGenerator" id="fromtable">
		<doc>A descriptor generator simply pulling a row from a database
			table.  This row is made available as the ``.metadata`` attribute.
			You also must give a field that the generator will pull a URL
			from; the generator arranges things so that the default dlget will
			simply redirect there.

			Note that the #this and #preview links DaCHS normally makes
			for descriptors from products are not added automatically here.  Try
			to at least provide #this.

			See also `Non-Product descriptor Generators`_.
		</doc>

		<setup imports="inspect, contextlib, gavo.protocols.datalink,
			gavo.svcs">
			<par key="tableName" description="The name of the table to pull the
				metadata row from (as a python value)." late="True"/>
			<par key="idColumn" description="The name of the table column to
				match the ID against (as a python value)." late="True"/>
			<par key="didPrefix" description="A URI to complete an identifier
				with with if it looks like a non-URI.  Leave empty to
				not do pubDID completion." late="True">base.NotGiven</par>
			<code>
				class FromrowDescriptor(datalink.DatalinkDescriptorMixin):
					"""a datalink descriptor just encapsulating a row from
					an arbitrary table.

					These have, as usual, pubDID and data, where data by default
					is just something redirecting to dataURL (or does a 404 if
					dataURL is NotGiven).

					The row matched is available in the metadata attribute.

					You'll usually construct these through its fromDB class
					method.
					"""
					suppressAutoLinks = True
					data = None
					forSemantics = soda.DEFAULT_SEMANTICS

					def __init__(self, pubDID, metadataRow):
						self.pubDID, self.metadata = pubDID, metadataRow

					@classmethod
					def fromDB(cls, did, tableName, idColumn):
						if not re.match("[\\w_.]+$", tableName):
							raise base.StructError(f"Invalid table name {tableName}")
						if not re.match("[\\w_.]+$", idColumn):
							raise base.StructError(f"Invalid column name {idColumn}")

						with base.getTableConn() as conn:
							rows = list(conn.queryToDicts(
								f"select * from {tableName} where {idColumn}=%(did)s",
								locals()))

						if not rows:
							raise svcs.UnknownURI(f"No dataset with id {did} known here")
						if len(rows)>1:
							raise base.ReportableError(
								f"Multiple datasets matched for {did}.  Bailing out.",
								hint="This is always an operator error – whatever is"
								" used as an ID in datalink must be a primary key"
								" in the managing table.")
						
						return cls(did, rows[0])
			</code>
		</setup>
		<code>
			if didPrefix:
				if not "://" in pubDID:
					pubDID  = didPrefix+pubDID

			return FromrowDescriptor.fromDB(pubDID, tableName, idColumn)
		</code>
	</procDef>


	<!-- ************************************************ async support -->

	<table id="datalinkjobs" onDisk="True" system="True">
		<meta name="description">A table managing datalink jobs submitted
			asynchronously (the dlasync renderer)</meta>

		<FEED source="//uws#uwsfields"/>
		<column name="pid" type="integer" 
				description="A unix pid to kill to make the job stop">
			<values nullLiteral="-1"/>
		</column>
	</table>

	<data id="import">
		<make table="datalinkjobs"/>
	</data>

</resource>
