summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorJoshua Harlow <harlowja@yahoo-inc.com>2014-10-09 17:55:36 -0700
committerJoshua Harlow <harlowja@yahoo-inc.com>2014-10-10 06:24:39 +0000
commitc90e36020a6993166bae1013402c30d827014317 (patch)
tree98b5e57aa4ef78affc29869ef9c093ff3ab90e4f /tools
parent1caaecc5d6b2aa4cde4a50e31d1d993fce7a66c4 (diff)
downloadtaskflow-c90e36020a6993166bae1013402c30d827014317.tar.gz
Add the database schema to the sqlalchemy docs
In order to show people that are reading the docs what the current schema for the database is create a helper tool that upgrades the schema to the newest version and then uses tabulate to create a restructured text version of that schema which is then included in the documentation. Change-Id: Id215f88430971a4a083f9739fb2ec59d971dc8fa
Diffstat (limited to 'tools')
-rwxr-xr-xtools/schema_generator.py83
1 files changed, 83 insertions, 0 deletions
diff --git a/tools/schema_generator.py b/tools/schema_generator.py
new file mode 100755
index 0000000..3685a0a
--- /dev/null
+++ b/tools/schema_generator.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2014 Yahoo! Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import contextlib
+import re
+
+import six
+import tabulate
+
+from taskflow.persistence.backends import impl_sqlalchemy
+
+NAME_MAPPING = {
+ 'flowdetails': 'Flow details',
+ 'atomdetails': 'Atom details',
+ 'logbooks': 'Logbooks',
+}
+CONN_CONF = {
+ # This uses an in-memory database (aka nothing is written)
+ "connection": "sqlite://",
+}
+TABLE_QUERY = "SELECT name, sql FROM sqlite_master WHERE type='table'"
+SCHEMA_QUERY = "pragma table_info(%s)"
+
+
+def to_bool_string(val):
+ if isinstance(val, (int, bool)):
+ return six.text_type(bool(val))
+ if not isinstance(val, six.string_types):
+ val = six.text_type(val)
+ if val.lower() in ('0', 'false'):
+ return 'False'
+ if val.lower() in ('1', 'true'):
+ return 'True'
+ raise ValueError("Unknown boolean input '%s'" % (val))
+
+
+def main():
+ backend = impl_sqlalchemy.SQLAlchemyBackend(CONN_CONF)
+ with contextlib.closing(backend) as backend:
+ # Make the schema exist...
+ with contextlib.closing(backend.get_connection()) as conn:
+ conn.upgrade()
+ # Now make a prettier version of that schema...
+ tables = backend.engine.execute(TABLE_QUERY)
+ table_names = [r[0] for r in tables]
+ for i, table_name in enumerate(table_names):
+ pretty_name = NAME_MAPPING.get(table_name, table_name)
+ print("*" + pretty_name + "*")
+ # http://www.sqlite.org/faq.html#q24
+ table_name = table_name.replace("\"", "\"\"")
+ rows = []
+ for r in backend.engine.execute(SCHEMA_QUERY % table_name):
+ # Cut out the numbers from things like VARCHAR(12) since
+ # this is not very useful to show users who just want to
+ # see the basic schema...
+ row_type = re.sub(r"\(.*?\)", "", r['type']).strip()
+ if not row_type:
+ raise ValueError("Row %s of table '%s' was empty after"
+ " cleaning" % (r['cid'], table_name))
+ rows.append([r['name'], row_type, to_bool_string(r['pk'])])
+ contents = tabulate.tabulate(
+ rows, headers=['Name', 'Type', 'Primary Key'],
+ tablefmt="rst")
+ print("\n%s" % contents.strip())
+ if i + 1 != len(table_names):
+ print("")
+
+
+if __name__ == '__main__':
+ main()