Repository: LMFDB/lmfdb

Issue:
Example upload files
The `reload` function in `db_backend.py` requires text files with a certain format (header, etc).  We should create a function that generates an example text file with one data row.

Question: should we use a different default separator than tab?


Discussion:
Please let us use a different separator.  ":" might be possible though I think some strongs are likely to have that character.  "|" might be safer.
@JohnCremona , we can use a different separator. The question is about which one should be the default. At the moment, we follow Postgres standard of `tab`.

I would vote for "|", better than using tabs
I just encountered this problem as I am trying to make a file to load later. I solved it by using 'copy_from' on one of the existing tables to get an example file. For me that was a good enough solution. We could mention this in the documentation for 'reload'. Would that solve the problem or did you envision something else? @roed314 

Resolving patch:
diff --git a/lmfdb/backend/searchtable.py b/lmfdb/backend/searchtable.py
--- a/lmfdb/backend/searchtable.py
+++ b/lmfdb/backend/searchtable.py
@@ -11,7 +11,7 @@
 from .base import number_types
 from .table import PostgresTable
 from .encoding import Json
-from .utils import IdentifierWrapper, filter_sql_injection, postgres_infix_ops
+from .utils import IdentifierWrapper, DelayCommit, filter_sql_injection, postgres_infix_ops
 
 
 class PostgresSearchTable(PostgresTable):
@@ -1059,6 +1059,42 @@ def random_sample(self, ratio, query={}, projection=1, mode=None, repeatable=Non
             cur = self._execute(selecter, values, buffered=True)
             return self._search_iterator(cur, search_cols, extra_cols, projection)
 
+    def copy_to_example(self, searchfile, extrafile=None, id=None, sep=u"|", commit=True):
+        """
+        This function writes files in the format used for copy_from and reload.
+        It writes the header and a single random row.
+
+        INPUT:
+
+        - ``searchfile`` -- a string, the filename to write data into for the search table
+        - ``extrafile`` -- a string,the filename to write data into for the extra table.
+            If there is an extra table, this argument is required.
+        - ``id`` -- an id to use for the example row (random if unspecified)
+        - ``sep`` -- a character to use as a separator between columns
+        """
+        self._check_file_input(searchfile, extrafile, {})
+        if id is None:
+            id = self.random({}, "id")
+            if id is None:
+                return self.copy_to(searchfile, extrafile, commit=commit, sep=sep)
+        tabledata = [
+            # tablename, cols, addid, write_header, filename
+            (self.search_table, ["id"] + self.search_cols, searchfile),
+            (self.extra_table, ["id"] + self.extra_cols, extrafile),
+        ]
+        with DelayCommit(self, commit):
+            for table, cols, filename in tabledata:
+                if filename is None:
+                    continue
+                types = [self.col_type[col] for col in cols]
+                header = "%s\n%s\n\n" % (sep.join(cols), sep.join(types))
+                select = SQL("SELECT {0} FROM {1} WHERE id = {2}").format(
+                    SQL(", ").join(map(Identifier, cols)),
+                    Identifier(table),
+                    Literal(id))
+                self._copy_to_select(select, filename, header=header, silent=True, sep=sep)
+                print("Wrote example to %s" % filename)
+
     ##################################################################
     # Convenience methods for accessing statistics                   #
     ##################################################################


Test patch: