about summary refs log tree commit diff
path: root/wqflask
diff options
context:
space:
mode:
authorzsloan2021-05-10 17:29:39 +0000
committerzsloan2021-05-10 17:29:39 +0000
commitc821aab3ee7b0fe42af10c2e72b6a43f9ec6f528 (patch)
tree86517882087412066d50e53288d2e70850f0eac9 /wqflask
parent06c24f18f27daa4e32a3041878b24bea5cc30ddc (diff)
parent0dab1e85cb197ed37d93facef575f8ef934eca81 (diff)
downloadgenenetwork2-c821aab3ee7b0fe42af10c2e72b6a43f9ec6f528.tar.gz
Merge branch 'testing' of github.com:genenetwork/genenetwork2 into testing
Diffstat (limited to 'wqflask')
-rw-r--r--wqflask/tests/unit/wqflask/api/test_gen_menu.py408
-rw-r--r--wqflask/utility/startup_config.py26
-rw-r--r--wqflask/wqflask/__init__.py21
-rw-r--r--wqflask/wqflask/api/gen_menu.py251
-rw-r--r--wqflask/wqflask/api/router.py8
-rw-r--r--wqflask/wqflask/gsearch.py115
-rw-r--r--wqflask/wqflask/templates/gsearch_gene.html15
-rw-r--r--wqflask/wqflask/templates/gsearch_pheno.html15
-rw-r--r--wqflask/wqflask/views.py13
9 files changed, 500 insertions, 372 deletions
diff --git a/wqflask/tests/unit/wqflask/api/test_gen_menu.py b/wqflask/tests/unit/wqflask/api/test_gen_menu.py
index fd0fe52e..743b3bde 100644
--- a/wqflask/tests/unit/wqflask/api/test_gen_menu.py
+++ b/wqflask/tests/unit/wqflask/api/test_gen_menu.py
@@ -2,7 +2,6 @@
 import unittest
 from unittest import mock
 
-from wqflask import app
 from wqflask.api.gen_menu import gen_dropdown_json
 from wqflask.api.gen_menu import get_species
 from wqflask.api.gen_menu import get_groups
@@ -18,8 +17,6 @@ class TestGenMenu(unittest.TestCase):
     """Tests for the gen_menu module"""
 
     def setUp(self):
-        self.app_context = app.app_context()
-        self.app_context.push()
         self.test_group = {
             'mouse': [
                 ['H_T1',
@@ -70,212 +67,239 @@ class TestGenMenu(unittest.TestCase):
             }
         }
 
-    def tearDown(self):
-        self.app_context.pop()
-
-    @mock.patch('wqflask.api.gen_menu.g')
-    def test_get_species(self, db_mock):
+    def test_get_species(self):
         """Test that assertion is raised when dataset and dataset_name
         are defined"""
-        db_mock.db.execute.return_value.fetchall.return_value = (
-            ('human', 'Human'),
-            ('mouse', 'Mouse'))
-        self.assertEqual(get_species(),
-                         [['human', 'Human'], ['mouse', 'Mouse']])
-        db_mock.db.execute.assert_called_once_with(
-            "SELECT Name, MenuName FROM Species ORDER BY OrderId"
-        )
-
-    @mock.patch('wqflask.api.gen_menu.g')
-    def test_get_groups(self, db_mock):
-        """Test that species groups are grouped correctly"""
-        db_mock.db.execute.return_value.fetchall.side_effect = [
-            # Mouse
-            (('BXD', 'BXD', None),
-             ('HLC', 'Liver: Normal Gene Expression with Genotypes (Merck)',
-              'Test')),
-            # Human
-            (('H_T1', "H_T", "DescriptionA"),
-             ('H_T2', "H_T'", None))
-        ]
-
-        self.assertEqual(get_groups([["human", "Human"], ["mouse", "Mouse"]]),
-                         self.test_group)
-
-        for name in ["mouse", "human"]:
-            db_mock.db.execute.assert_any_call(
-                ("SELECT InbredSet.Name, InbredSet.FullName, " +
-                 "IFNULL(InbredSet.Family, 'None') "
-                 + "FROM InbredSet, Species WHERE Species.Name "
-                 + "= '{}' AND InbredSet.SpeciesId = Species.Id GROUP by "
-                 + "InbredSet.Name ORDER BY IFNULL(InbredSet.FamilyOrder, "
-                 + "InbredSet.FullName) ASC, IFNULL(InbredSet.Family, "
-                 + "InbredSet.FullName) ASC, InbredSet.FullName ASC, "
-                 + "InbredSet.MenuOrderId ASC").format(name)
+        db_mock = mock.MagicMock()
+        with db_mock.cursor() as cursor:
+            cursor.fetchall.return_value = (
+                ('human', 'Human'),
+                ('mouse', 'Mouse'))
+            self.assertEqual(get_species(db_mock),
+                             [['human', 'Human'], ['mouse', 'Mouse']])
+            cursor.execute.assert_called_once_with(
+                "SELECT Name, MenuName FROM Species ORDER BY OrderId"
             )
 
-    @mock.patch('wqflask.api.gen_menu.g')
-    def test_phenotypes_exist_called_with_correct_query(self, db_mock):
+    def test_get_groups(self):
+        """Test that species groups are grouped correctly"""
+        db_mock = mock.MagicMock()
+        with db_mock.cursor() as cursor:
+            cursor.fetchall.side_effect = [
+                # Mouse
+                (('BXD', 'BXD', None),
+                 ('HLC', ('Liver: Normal Gene Expression '
+                          'with Genotypes (Merck)'),
+                  'Test')),
+                # Human
+                (('H_T1', "H_T", "DescriptionA"),
+                 ('H_T2', "H_T'", None))
+            ]
+            self.assertEqual(get_groups([["human", "Human"],
+                                         ["mouse", "Mouse"]],
+                                        db_mock),
+                             self.test_group)
+
+            for name in ["mouse", "human"]:
+                cursor.execute.assert_any_call(
+                    ("SELECT InbredSet.Name, InbredSet.FullName, "
+                     "IFNULL(InbredSet.Family, 'None') "
+                     "FROM InbredSet, Species WHERE Species.Name "
+                     "= '{}' AND InbredSet.SpeciesId = Species.Id GROUP by "
+                     "InbredSet.Name ORDER BY IFNULL(InbredSet.FamilyOrder, "
+                     "InbredSet.FullName) ASC, IFNULL(InbredSet.Family, "
+                     "InbredSet.FullName) ASC, InbredSet.FullName ASC, "
+                     "InbredSet.MenuOrderId ASC").format(name)
+                )
+
+    def test_phenotypes_exist_called_with_correct_query(self):
         """Test that phenotypes_exist is called with the correct query"""
-        db_mock.db.execute.return_value.fetchone.return_value = None
-        phenotypes_exist("test")
-        db_mock.db.execute.assert_called_with(
-            "SELECT Name FROM PublishFreeze "
-            "WHERE PublishFreeze.Name = 'testPublish'"
-        )
-
-    @mock.patch('wqflask.api.gen_menu.g')
-    def test_phenotypes_exist_with_falsy_values(self, db_mock):
+        db_mock = mock.MagicMock()
+        with db_mock.cursor() as cursor:
+            cursor.fetchone.return_value = None
+            phenotypes_exist("test", db_mock)
+            cursor.execute.assert_called_with(
+                "SELECT Name FROM PublishFreeze "
+                "WHERE PublishFreeze.Name = 'testPublish'"
+            )
+
+    def test_phenotypes_exist_with_falsy_values(self):
         """Test that phenotype check returns correctly when given
         a None value"""
-        for x in [None, False, (), [], ""]:
-            db_mock.db.execute.return_value.fetchone.return_value = x
-            self.assertFalse(phenotypes_exist("test"))
-
-    @mock.patch('wqflask.api.gen_menu.g')
-    def test_phenotypes_exist_with_truthy_value(self, db_mock):
-        """Test that phenotype check returns correctly when given Truthy """
-        for x in ["x", ("result"), ["result"], [1]]:
-            db_mock.db.execute.return_value.fetchone.return_value = (x)
-            self.assertTrue(phenotypes_exist("test"))
-
-    @mock.patch('wqflask.api.gen_menu.g')
-    def test_genotypes_exist_called_with_correct_query(self, db_mock):
+        db_mock = mock.MagicMock()
+        with db_mock.cursor() as cursor:
+            for x in [None, False, (), [], ""]:
+                cursor.fetchone.return_value = x
+            self.assertFalse(phenotypes_exist("test", db_mock))
+
+    def test_phenotypes_exist_with_truthy_value(self):
+        """Test that phenotype check returns correctly when given Truthy"""
+        db_mock = mock.MagicMock()
+        with db_mock.cursor() as conn:
+            with conn.cursor() as cursor:
+                for x in ["x", ("result"), ["result"], [1]]:
+                    cursor.fetchone.return_value = (x)
+                self.assertTrue(phenotypes_exist("test", db_mock))
+
+    def test_genotypes_exist_called_with_correct_query(self):
         """Test that genotypes_exist is called with the correct query"""
-        db_mock.db.execute.return_value.fetchone.return_value = None
-        genotypes_exist("test")
-        db_mock.db.execute.assert_called_with(
-            "SELECT Name FROM GenoFreeze WHERE GenoFreeze.Name = 'testGeno'"
-        )
-
-    @mock.patch('wqflask.api.gen_menu.g')
-    def test_genotypes_exist_with_falsy_values(self, db_mock):
-        """Test that genotype check returns correctly when given
-        a None value"""
-        for x in [None, False, (), [], ""]:
-            db_mock.db.execute.return_value.fetchone.return_value = x
-            self.assertFalse(genotypes_exist("test"))
+        db_mock = mock.MagicMock()
+        with db_mock.cursor() as cursor:
+            cursor.fetchone.return_value = None
+            genotypes_exist("test", db_mock)
+            cursor.execute.assert_called_with(
+                "SELECT Name FROM GenoFreeze WHERE "
+                "GenoFreeze.Name = 'testGeno'"
+            )
+
+    def test_genotypes_exist_with_falsy_values(self):
+        """Test that genotype check returns correctly when given a None value
+
+        """
+        db_mock = mock.MagicMock()
+        with db_mock.cursor() as cursor:
+            for x in [None, False, (), [], ""]:
+                cursor.fetchone.return_value = x
+                self.assertFalse(genotypes_exist("test", db_mock))
 
-    @mock.patch('wqflask.api.gen_menu.g')
-    def test_genotypes_exist_with_truthy_value(self, db_mock):
+    def test_genotypes_exist_with_truthy_value(self):
         """Test that genotype check returns correctly when given Truthy """
-        for x in ["x", ("result"), ["result"], [1]]:
-            db_mock.db.execute.return_value.fetchone.return_value = (x)
-            self.assertTrue(phenotypes_exist("test"))
+        db_mock = mock.MagicMock()
+        with db_mock.cursor() as cursor:
+            for x in ["x", ("result"), ["result"], [1]]:
+                cursor.fetchone.return_value = (x)
+                self.assertTrue(phenotypes_exist("test", db_mock))
 
-    @mock.patch('wqflask.api.gen_menu.g')
-    def test_build_datasets_with_type_phenotypes(self, db_mock):
+    def test_build_datasets_with_type_phenotypes(self):
         """Test that correct dataset is returned for a phenotype type"""
-        db_mock.db.execute.return_value.fetchall.return_value = (
-            (602, "BXDPublish", "BXD Published Phenotypes"),
-        )
-        self.assertEqual(build_datasets("Mouse", "BXD", "Phenotypes"),
-                         [['602', "BXDPublish", "BXD Published Phenotypes"]])
-        db_mock.db.execute.assert_called_with(
-            "SELECT InfoFiles.GN_AccesionId, PublishFreeze.Name, "
-            + "PublishFreeze.FullName FROM InfoFiles, PublishFreeze, "
-            + "InbredSet WHERE InbredSet.Name = 'BXD' AND "
-            + "PublishFreeze.InbredSetId = InbredSet.Id AND "
-            + "InfoFiles.InfoPageName = PublishFreeze.Name "
-            + "ORDER BY PublishFreeze.CreateTime ASC"
-        )
-        self.assertEqual(build_datasets("Mouse", "MDP", "Phenotypes"),
-                         [['602', "BXDPublish", "Mouse Phenome Database"]])
-
-        db_mock.db.execute.return_value.fetchall.return_value = ()
-        db_mock.db.execute.return_value.fetchone.return_value = (
-            "BXDPublish", "Mouse Phenome Database"
-        )
-        self.assertEqual(build_datasets("Mouse", "MDP", "Phenotypes"),
-                         [["None", "BXDPublish", "Mouse Phenome Database"]])
-
-    @mock.patch('wqflask.api.gen_menu.g')
-    def test_build_datasets_with_type_phenotypes_and_no_results(self, db_mock):
+        db_mock = mock.MagicMock()
+        with db_mock.cursor() as cursor:
+            cursor.fetchall.return_value = (
+                (602, "BXDPublish", "BXD Published Phenotypes"),
+            )
+            self.assertEqual(build_datasets("Mouse", "BXD",
+                                            "Phenotypes", db_mock),
+                             [['602', "BXDPublish",
+                               "BXD Published Phenotypes"]])
+            cursor.execute.assert_called_with(
+                "SELECT InfoFiles.GN_AccesionId, PublishFreeze.Name, "
+                + "PublishFreeze.FullName FROM InfoFiles, PublishFreeze, "
+                + "InbredSet WHERE InbredSet.Name = 'BXD' AND "
+                + "PublishFreeze.InbredSetId = InbredSet.Id AND "
+                + "InfoFiles.InfoPageName = PublishFreeze.Name "
+                + "ORDER BY PublishFreeze.CreateTime ASC"
+            )
+            self.assertEqual(build_datasets("Mouse", "MDP",
+                                            "Phenotypes", db_mock),
+                             [['602', "BXDPublish",
+                               "Mouse Phenome Database"]])
+
+            cursor.fetchall.return_value = ()
+            cursor.fetchone.return_value = (
+                "BXDPublish", "Mouse Phenome Database"
+            )
+            self.assertEqual(build_datasets("Mouse", "MDP",
+                                            "Phenotypes", db_mock),
+                             [["None", "BXDPublish",
+                               "Mouse Phenome Database"]])
+
+    def test_build_datasets_with_type_phenotypes_and_no_results(self):
         """Test that correct dataset is returned for a phenotype type with no
         results
 
         """
-        db_mock.db.execute.return_value.fetchall.return_value = None
-        db_mock.db.execute.return_value.fetchone.return_value = (121,
-                                                                 "text value")
-        self.assertEqual(build_datasets("Mouse", "BXD", "Phenotypes"),
-                         [["None", "121", "text value"]])
-        db_mock.db.execute.assert_called_with(
-            "SELECT PublishFreeze.Name, PublishFreeze.FullName "
-            "FROM PublishFreeze, InbredSet "
-            "WHERE InbredSet.Name = 'BXD' AND "
-            "PublishFreeze.InbredSetId = InbredSet.Id "
-            "ORDER BY PublishFreeze.CreateTime ASC"
-        )
-
-    @mock.patch('wqflask.api.gen_menu.g')
-    def test_build_datasets_with_type_genotypes(self, db_mock):
+        db_mock = mock.MagicMock()
+        with db_mock.cursor() as cursor:
+            cursor.fetchall.return_value = None
+            cursor.fetchone.return_value = (121,
+                                            "text value")
+            self.assertEqual(build_datasets("Mouse", "BXD",
+                                            "Phenotypes", db_mock),
+                             [["None", "121",
+                               "text value"]])
+            cursor.execute.assert_called_with(
+                "SELECT PublishFreeze.Name, PublishFreeze.FullName "
+                "FROM PublishFreeze, InbredSet "
+                "WHERE InbredSet.Name = 'BXD' AND "
+                "PublishFreeze.InbredSetId = InbredSet.Id "
+                "ORDER BY PublishFreeze.CreateTime ASC"
+            )
+
+    def test_build_datasets_with_type_genotypes(self):
         """Test that correct dataset is returned for a phenotype type"""
-        db_mock.db.execute.return_value.fetchone.return_value = (
-            635, "HLCPublish", "HLC Published Genotypes"
-        )
-
-        self.assertEqual(build_datasets("Mouse", "HLC", "Genotypes"),
-                         [["635", "HLCGeno", "HLC Genotypes"]])
-        db_mock.db.execute.assert_called_with(
-            "SELECT InfoFiles.GN_AccesionId FROM InfoFiles, "
-            "GenoFreeze, InbredSet WHERE InbredSet.Name = 'HLC' AND "
-            "GenoFreeze.InbredSetId = InbredSet.Id AND "
-            "InfoFiles.InfoPageName = GenoFreeze.ShortName "
-            + "ORDER BY GenoFreeze.CreateTime DESC"
-        )
-        db_mock.db.execute.return_value.fetchone.return_value = ()
-        self.assertEqual(build_datasets("Mouse", "HLC", "Genotypes"),
-                         [["None", "HLCGeno", "HLC Genotypes"]])
-
-    @mock.patch('wqflask.api.gen_menu.g')
-    def test_build_datasets_with_type_mrna(self, db_mock):
+        db_mock = mock.MagicMock()
+        with db_mock.cursor() as cursor:
+            cursor.fetchone.return_value = (
+                635, "HLCPublish", "HLC Published Genotypes"
+            )
+            self.assertEqual(build_datasets("Mouse", "HLC",
+                                            "Genotypes", db_mock),
+                             [["635", "HLCGeno", "HLC Genotypes"]])
+            cursor.execute.assert_called_with(
+                "SELECT InfoFiles.GN_AccesionId FROM InfoFiles, "
+                "GenoFreeze, InbredSet WHERE InbredSet.Name = 'HLC' AND "
+                "GenoFreeze.InbredSetId = InbredSet.Id AND "
+                "InfoFiles.InfoPageName = GenoFreeze.ShortName "
+                "ORDER BY GenoFreeze.CreateTime DESC"
+            )
+            cursor.fetchone.return_value = ()
+            self.assertEqual(build_datasets("Mouse", "HLC",
+                                            "Genotypes", db_mock),
+                             [["None", "HLCGeno", "HLC Genotypes"]])
+
+    def test_build_datasets_with_type_mrna(self):
         """Test that correct dataset is returned for a mRNA
         expression/ Probeset"""
-        db_mock.db.execute.return_value.fetchall.return_value = (
-            (112, "HC_M2_0606_P",
-             "Hippocampus Consortium M430v2 (Jun06) PDNN"), )
-        self.assertEqual(build_datasets("Mouse", "HLC", "mRNA"), [[
-            "112", 'HC_M2_0606_P', "Hippocampus Consortium M430v2 (Jun06) PDNN"
-        ]])
-        db_mock.db.execute.assert_called_once_with(
-            "SELECT ProbeSetFreeze.Id, ProbeSetFreeze.Name, "
-            + "ProbeSetFreeze.FullName FROM ProbeSetFreeze, "
-            + "ProbeFreeze, InbredSet, Tissue, Species WHERE "
-            + "Species.Name = 'Mouse' AND Species.Id = "
-            + "InbredSet.SpeciesId AND InbredSet.Name = 'HLC' AND "
-            + "ProbeSetFreeze.ProbeFreezeId = ProbeFreeze.Id AND "
-            + "Tissue.Name = 'mRNA' AND ProbeFreeze.TissueId = "
-            + "Tissue.Id AND ProbeFreeze.InbredSetId = InbredSet.Id AND "
-            + "ProbeSetFreeze.public > 0 "
-            + "ORDER BY -ProbeSetFreeze.OrderList DESC, ProbeSetFreeze.CreateTime DESC")
+        db_mock = mock.MagicMock()
+        with db_mock.cursor() as cursor:
+            cursor.fetchall.return_value = (
+                (112, "HC_M2_0606_P",
+                 "Hippocampus Consortium M430v2 (Jun06) PDNN"), )
+            self.assertEqual(build_datasets("Mouse",
+                                            "HLC", "mRNA", db_mock),
+                             [["112", 'HC_M2_0606_P',
+                               "Hippocampus Consortium M430v2 (Jun06) PDNN"
+                               ]])
+            cursor.execute.assert_called_once_with(
+                "SELECT ProbeSetFreeze.Id, ProbeSetFreeze.Name, "
+                "ProbeSetFreeze.FullName FROM ProbeSetFreeze, "
+                "ProbeFreeze, InbredSet, Tissue, Species WHERE "
+                "Species.Name = 'Mouse' AND Species.Id = "
+                "InbredSet.SpeciesId AND InbredSet.Name = 'HLC' AND "
+                "ProbeSetFreeze.ProbeFreezeId = ProbeFreeze.Id AND "
+                "Tissue.Name = 'mRNA' AND ProbeFreeze.TissueId = "
+                "Tissue.Id AND ProbeFreeze.InbredSetId = InbredSet.Id AND "
+                "ProbeSetFreeze.public > 0 "
+                "ORDER BY -ProbeSetFreeze.OrderList DESC, "
+                "ProbeSetFreeze.CreateTime DESC")
 
     @mock.patch('wqflask.api.gen_menu.build_datasets')
-    @mock.patch('wqflask.api.gen_menu.g')
-    def test_build_types(self, db_mock, datasets_mock):
+    def test_build_types(self, datasets_mock):
         """Test that correct tissue metadata is returned"""
+        db_mock = mock.MagicMock()
         datasets_mock.return_value = [
             ["112", 'HC_M2_0606_P',
                 "Hippocampus Consortium M430v2 (Jun06) PDNN"]
         ]
-        db_mock.db.execute.return_value.fetchall.return_value = (
-            ('Mouse Tissue'), ('Human Tissue'), ('Rat Tissue')
-        )
-        self.assertEqual(build_types('mouse', 'random group'),
-                         [['M', 'M', 'Molecular Traits'],
-                          ['H', 'H', 'Molecular Traits'],
-                          ['R', 'R', 'Molecular Traits']])
-        db_mock.db.execute.assert_called_once_with(
-            "SELECT DISTINCT Tissue.Name "
-            + "FROM ProbeFreeze, ProbeSetFreeze, InbredSet, "
-            + "Tissue, Species WHERE Species.Name = 'mouse' "
-            + "AND Species.Id = InbredSet.SpeciesId AND "
-            + "InbredSet.Name = 'random group' AND "
-            + "ProbeFreeze.TissueId = Tissue.Id AND "
-            + "ProbeFreeze.InbredSetId = InbredSet.Id AND "
-            + "ProbeSetFreeze.ProbeFreezeId = ProbeFreeze.Id "
-            + "ORDER BY Tissue.Name"
-        )
+        with db_mock.cursor() as cursor:
+            cursor.fetchall.return_value = (
+                ('Mouse Tissue'), ('Human Tissue'), ('Rat Tissue')
+            )
+            self.assertEqual(build_types('mouse', 'random group', db_mock),
+                             [['M', 'M', 'Molecular Traits'],
+                              ['H', 'H', 'Molecular Traits'],
+                              ['R', 'R', 'Molecular Traits']])
+            cursor.execute.assert_called_once_with(
+                "SELECT DISTINCT Tissue.Name "
+                "FROM ProbeFreeze, ProbeSetFreeze, InbredSet, "
+                "Tissue, Species WHERE Species.Name = 'mouse' "
+                "AND Species.Id = InbredSet.SpeciesId AND "
+                "InbredSet.Name = 'random group' AND "
+                "ProbeFreeze.TissueId = Tissue.Id AND "
+                "ProbeFreeze.InbredSetId = InbredSet.Id AND "
+                "ProbeSetFreeze.ProbeFreezeId = ProbeFreeze.Id "
+                "ORDER BY Tissue.Name"
+            )
 
     @mock.patch('wqflask.api.gen_menu.build_types')
     @mock.patch('wqflask.api.gen_menu.genotypes_exist')
@@ -297,7 +321,9 @@ class TestGenMenu(unittest.TestCase):
         build_types_mock.return_value = [
             ['M', 'M', 'Molecular Trait Datasets']
         ]
-        self.assertEqual(get_types(self.test_group), expected_result)
+        self.assertEqual(get_types(self.test_group,
+                                   mock.MagicMock()),
+                         expected_result)
 
     @mock.patch('wqflask.api.gen_menu.build_types')
     @mock.patch('wqflask.api.gen_menu.genotypes_exist')
@@ -315,10 +341,8 @@ class TestGenMenu(unittest.TestCase):
         genotypes_exist_mock.return_value = False
 
         build_types_mock.return_value = []
-        self.assertEqual(get_types(self.test_group), {
-            'mouse': {},
-            'human': {}
-        })
+        self.assertEqual(get_types(self.test_group, mock.MagicMock()),
+                         {'mouse': {}, 'human': {}})
 
     @mock.patch('wqflask.api.gen_menu.build_types')
     @mock.patch('wqflask.api.gen_menu.genotypes_exist')
@@ -345,7 +369,7 @@ class TestGenMenu(unittest.TestCase):
             'human': {
                 'HLC': [['M', 'M', 'Molecular Trait Datasets']],
                 'BXD': [['M', 'M', 'Molecular Trait Datasets']]}}
-        self.assertEqual(get_types(self.test_group),
+        self.assertEqual(get_types(self.test_group, mock.MagicMock()),
                          expected_result)
 
     @mock.patch('wqflask.api.gen_menu.build_datasets')
@@ -367,7 +391,7 @@ class TestGenMenu(unittest.TestCase):
                       'BXD': {'Genotypes': 'Test',
                               'M': 'Test',
                               'Phenotypes': 'Test'}}}
-        self.assertEqual(get_datasets(self.test_type),
+        self.assertEqual(get_datasets(self.test_type, mock.MagicMock()),
                          expected_result)
 
     @mock.patch('wqflask.api.gen_menu.build_datasets')
@@ -381,7 +405,7 @@ class TestGenMenu(unittest.TestCase):
                 'H_T1': {}},
             'human': {'HLC': {},
                       'BXD': {}}}
-        self.assertEqual(get_datasets(self.test_type),
+        self.assertEqual(get_datasets(self.test_type, mock.MagicMock()),
                          expected_result)
 
     @mock.patch('wqflask.api.gen_menu.get_datasets')
@@ -411,4 +435,4 @@ class TestGenMenu(unittest.TestCase):
             'groups': ['groupA', 'groupB', 'groupC', 'groupD'],
             'species': ['speciesA', 'speciesB', 'speciesC', 'speciesD']}
 
-        self.assertEqual(gen_dropdown_json(), expected_result)
+        self.assertEqual(gen_dropdown_json(mock.MagicMock()), expected_result)
diff --git a/wqflask/utility/startup_config.py b/wqflask/utility/startup_config.py
index 6ef759e0..56d0af6f 100644
--- a/wqflask/utility/startup_config.py
+++ b/wqflask/utility/startup_config.py
@@ -1,9 +1,12 @@
 
 from wqflask import app
-from utility.tools import WEBSERVER_MODE, show_settings, get_setting_int, get_setting, get_setting_bool
 
-import utility.logger
-logger = utility.logger.getLogger(__name__)
+from utility.tools import WEBSERVER_MODE
+from utility.tools import show_settings
+from utility.tools import get_setting_int
+from utility.tools import get_setting
+from utility.tools import get_setting_bool
+
 
 BLUE = '\033[94m'
 GREEN = '\033[92m'
@@ -16,27 +19,22 @@ def app_config():
     if not app.config.get('SECRET_KEY'):
         import os
         app.config['SECRET_KEY'] = str(os.urandom(24))
-
     mode = WEBSERVER_MODE
     if mode == "DEV" or mode == "DEBUG":
         app.config['TEMPLATES_AUTO_RELOAD'] = True
-        # if mode == "DEBUG":
-        #     app.config['EXPLAIN_TEMPLATE_LOADING'] = True <--- use overriding app param instead
+
     print("==========================================")
+
     show_settings()
 
     port = get_setting_int("SERVER_PORT")
 
     if get_setting_bool("USE_GN_SERVER"):
-        print(
-            ("GN2 API server URL is [" + BLUE + get_setting("GN_SERVER_URL") + ENDC + "]"))
+        print(f"GN2 API server URL is [{BLUE}GN_SERVER_URL{ENDC}]")
         import requests
         page = requests.get(get_setting("GN_SERVER_URL"))
         if page.status_code != 200:
             raise Exception("API server not found!")
-
-    # import utility.elasticsearch_tools as es
-    # es.test_elasticsearch_connection()
-
-    print(("GN2 is running. Visit %s[http://localhost:%s/%s](%s)" %
-           (BLUE, str(port), ENDC, get_setting("WEBSERVER_URL"))))
+    print(f"GN2 is running. Visit {BLUE}"
+          f"[http://localhost:{str(port)}/{ENDC}]"
+          f"({get_setting('WEBSERVER_URL')})")
diff --git a/wqflask/wqflask/__init__.py b/wqflask/wqflask/__init__.py
index bf5e094b..2e94dd01 100644
--- a/wqflask/wqflask/__init__.py
+++ b/wqflask/wqflask/__init__.py
@@ -5,6 +5,8 @@ import jinja2
 
 from flask import g
 from flask import Flask
+from typing import Tuple
+from urllib.parse import urlparse
 from utility import formatting
 from wqflask.markdown_routes import glossary_blueprint
 from wqflask.markdown_routes import references_blueprint
@@ -16,9 +18,28 @@ from wqflask.markdown_routes import blogs_blueprint
 
 app = Flask(__name__)
 
+
+# Helper function for getting the SQL objects
+def parse_db_url(sql_uri: str) -> Tuple:
+    """Parse SQL_URI env variable from an sql URI
+    e.g. 'mysql://user:pass@host_name/db_name'
+
+    """
+    parsed_db = urlparse(sql_uri)
+    return (parsed_db.hostname, parsed_db.username,
+            parsed_db.password, parsed_db.path[1:])
+
+
 # See http://flask.pocoo.org/docs/config/#configuring-from-files
 # Note no longer use the badly named WQFLASK_OVERRIDES (nyi)
 app.config.from_envvar('GN2_SETTINGS')
+
+DB_HOST, DB_USER, DB_PASS, DB_NAME = parse_db_url(app.config.get('SQL_URI'))
+app.config["DB_HOST"] = DB_HOST
+app.config["DB_USER"] = DB_USER
+app.config["DB_PASS"] = DB_PASS
+app.config["DB_NAME"] = DB_NAME
+
 app.jinja_env.globals.update(
     undefined=jinja2.StrictUndefined,
     numify=formatting.numify)
diff --git a/wqflask/wqflask/api/gen_menu.py b/wqflask/wqflask/api/gen_menu.py
index 7f4ec1bc..0c1120ab 100644
--- a/wqflask/wqflask/api/gen_menu.py
+++ b/wqflask/wqflask/api/gen_menu.py
@@ -1,15 +1,12 @@
-from flask import g
-
-
-def gen_dropdown_json():
+def gen_dropdown_json(conn):
     """Generates and outputs (as json file) the data for the main dropdown menus on
     the home page
     """
 
-    species = get_species()
-    groups = get_groups(species)
-    types = get_types(groups)
-    datasets = get_datasets(types)
+    species = get_species(conn)
+    groups = get_groups(species, conn)
+    types = get_types(groups, conn)
+    datasets = get_datasets(types, conn)
 
     data = dict(species=species,
                 groups=groups,
@@ -19,48 +16,50 @@ def gen_dropdown_json():
     return data
 
 
-def get_species():
+def get_species(conn):
     """Build species list"""
-    results = g.db.execute(
-        "SELECT Name, MenuName FROM Species ORDER BY OrderId").fetchall()
-    return [[name, menu_name] for name, menu_name in results]
+    with conn.cursor() as cursor:
+        cursor.execute("SELECT Name, MenuName FROM Species "
+                       "ORDER BY OrderId")
+        results = cursor.fetchall()
+        return [[name, menu_name] for name, menu_name in results]
 
 
-def get_groups(species):
+def get_groups(species, conn):
     """Build groups list"""
     groups = {}
-    for species_name, _species_full_name in species:
-        groups[species_name] = []
-
-        results = g.db.execute(
-            ("SELECT InbredSet.Name, InbredSet.FullName, "
-             "IFNULL(InbredSet.Family, 'None') "
-             "FROM InbredSet, Species WHERE Species.Name = '{}' "
-             "AND InbredSet.SpeciesId = Species.Id GROUP by InbredSet.Name "
-             "ORDER BY IFNULL(InbredSet.FamilyOrder, InbredSet.FullName) "
-             "ASC, IFNULL(InbredSet.Family, InbredSet.FullName) ASC, "
-             "InbredSet.FullName ASC, InbredSet.MenuOrderId ASC")
-            .format(species_name)).fetchall()
-
-        for result in results:
-            family_name = "Family:" + str(result[2])
-            groups[species_name].append(
-                [str(result[0]), str(result[1]), family_name])
-
+    with conn.cursor() as cursor:
+        for species_name, _species_full_name in species:
+            groups[species_name] = []
+            cursor.execute(
+                ("SELECT InbredSet.Name, InbredSet.FullName, "
+                 "IFNULL(InbredSet.Family, 'None') "
+                 "FROM InbredSet, Species WHERE Species.Name = '{}' "
+                 "AND InbredSet.SpeciesId = Species.Id GROUP by "
+                 "InbredSet.Name ORDER BY IFNULL(InbredSet.FamilyOrder, "
+                 "InbredSet.FullName) ASC, IFNULL(InbredSet.Family, "
+                 "InbredSet.FullName) ASC, InbredSet.FullName ASC, "
+                 "InbredSet.MenuOrderId ASC")
+                .format(species_name))
+            results = cursor.fetchall()
+            for result in results:
+                family_name = "Family:" + str(result[2])
+                groups[species_name].append(
+                    [str(result[0]), str(result[1]), family_name])
     return groups
 
 
-def get_types(groups):
+def get_types(groups, conn):
     """Build types list"""
     types = {}
 
     for species, group_dict in list(groups.items()):
         types[species] = {}
         for group_name, _group_full_name, _family_name in group_dict:
-            if phenotypes_exist(group_name):
+            if phenotypes_exist(group_name, conn):
                 types[species][group_name] = [
                     ("Phenotypes", "Traits and Cofactors", "Phenotypes")]
-            if genotypes_exist(group_name):
+            if genotypes_exist(group_name, conn):
                 if group_name in types[species]:
                     types[species][group_name] += [
                         ("Genotypes", "DNA Markers and SNPs", "Genotypes")]
@@ -68,11 +67,11 @@ def get_types(groups):
                     types[species][group_name] = [
                         ("Genotypes", "DNA Markers and SNPs", "Genotypes")]
             if group_name in types[species]:
-                types_list = build_types(species, group_name)
+                types_list = build_types(species, group_name, conn)
                 if len(types_list) > 0:
                     types[species][group_name] += types_list
             else:
-                types_list = build_types(species, group_name)
+                types_list = build_types(species, group_name, conn)
                 if len(types_list) > 0:
                     types[species][group_name] = types_list
                 else:
@@ -83,22 +82,28 @@ def get_types(groups):
     return types
 
 
-def phenotypes_exist(group_name):
-    results = g.db.execute(
-        ("SELECT Name FROM PublishFreeze "
-         "WHERE PublishFreeze.Name = "
-         "'{}'").format(group_name + "Publish")).fetchone()
+def phenotypes_exist(group_name, conn):
+    results = []
+    with conn.cursor() as cursor:
+        cursor.execute(
+            ("SELECT Name FROM PublishFreeze "
+             "WHERE PublishFreeze.Name = "
+             "'{}'").format(group_name + "Publish"))
+        results = cursor.fetchone()
     return bool(results)
 
 
-def genotypes_exist(group_name):
-    results = g.db.execute(
-        ("SELECT Name FROM GenoFreeze " +
-         "WHERE GenoFreeze.Name = '{}'").format(group_name + "Geno")).fetchone()
-    return bool(results)
+def genotypes_exist(group_name, conn):
+    with conn.cursor() as cursor:
+        cursor.execute(
+            ("SELECT Name FROM GenoFreeze " +
+             "WHERE GenoFreeze.Name = '{}'").format(
+                 group_name + "Geno"))
+        results = cursor.fetchone()
+        return bool(results)
 
 
-def build_types(species, group):
+def build_types(species, group, conn):
     """Fetches tissues
 
     Gets the tissues with data for this species/group
@@ -116,17 +121,19 @@ def build_types(species, group):
              "ORDER BY Tissue.Name").format(species, group)
 
     results = []
-    for result in g.db.execute(query).fetchall():
-        if bool(result):
-            these_datasets = build_datasets(species, group, result[0])
-            if len(these_datasets) > 0:
-                results.append([str(result[0]), str(result[0]),
-                                "Molecular Traits"])
-
+    with conn.cursor() as cursor:
+        cursor.execute(query)
+        for result in cursor.fetchall():
+            if bool(result):
+                these_datasets = build_datasets(species,
+                                                group, result[0], conn)
+                if len(these_datasets) > 0:
+                    results.append([str(result[0]), str(result[0]),
+                                    "Molecular Traits"])
     return results
 
 
-def get_datasets(types):
+def get_datasets(types, conn):
     """Build datasets list"""
     datasets = {}
     for species, group_dict in list(types.items()):
@@ -134,83 +141,89 @@ def get_datasets(types):
         for group, type_list in list(group_dict.items()):
             datasets[species][group] = {}
             for type_name in type_list:
-                these_datasets = build_datasets(species, group, type_name[0])
+                these_datasets = build_datasets(species, group,
+                                                type_name[0], conn)
                 if bool(these_datasets):
                     datasets[species][group][type_name[0]] = these_datasets
 
     return datasets
 
 
-def build_datasets(species, group, type_name):
+def build_datasets(species, group, type_name, conn):
     """Gets dataset names from database"""
     dataset_text = dataset_value = None
     datasets = []
-    if type_name == "Phenotypes":
-        results = g.db.execute(
-            ("SELECT InfoFiles.GN_AccesionId, PublishFreeze.Name, "
-             "PublishFreeze.FullName FROM InfoFiles, PublishFreeze, "
-             "InbredSet WHERE InbredSet.Name = '{}' AND "
-             "PublishFreeze.InbredSetId = InbredSet.Id AND "
-             "InfoFiles.InfoPageName = PublishFreeze.Name "
-             "ORDER BY PublishFreeze.CreateTime ASC").format(group)).fetchall()
-        if bool(results):
-            for result in results:
-                dataset_id = str(result[0])
-                dataset_value = str(result[1])
-                dataset_text = str(result[2])
-                if group == 'MDP':
-                    dataset_text = "Mouse Phenome Database"
-
+    with conn.cursor() as cursor:
+        if type_name == "Phenotypes":
+            cursor.execute(
+                ("SELECT InfoFiles.GN_AccesionId, PublishFreeze.Name, "
+                 "PublishFreeze.FullName FROM InfoFiles, PublishFreeze, "
+                 "InbredSet WHERE InbredSet.Name = '{}' AND "
+                 "PublishFreeze.InbredSetId = InbredSet.Id AND "
+                 "InfoFiles.InfoPageName = PublishFreeze.Name "
+                 "ORDER BY PublishFreeze.CreateTime ASC").format(group))
+            results = cursor.fetchall()
+            if bool(results):
+                for result in results:
+                    dataset_id = str(result[0])
+                    dataset_value = str(result[1])
+                    dataset_text = str(result[2])
+                    if group == 'MDP':
+                        dataset_text = "Mouse Phenome Database"
+
+                    datasets.append([dataset_id, dataset_value, dataset_text])
+            else:
+                cursor.execute(
+                    ("SELECT PublishFreeze.Name, PublishFreeze.FullName "
+                     "FROM PublishFreeze, InbredSet "
+                     "WHERE InbredSet.Name = '{}' AND "
+                     "PublishFreeze.InbredSetId = InbredSet.Id "
+                     "ORDER BY PublishFreeze.CreateTime ASC")
+                    .format(group))
+                result = cursor.fetchone()
+                dataset_id = "None"
+                dataset_value = str(result[0])
+                dataset_text = str(result[1])
                 datasets.append([dataset_id, dataset_value, dataset_text])
-        else:
-            result = g.db.execute(
-                ("SELECT PublishFreeze.Name, PublishFreeze.FullName "
-                 "FROM PublishFreeze, InbredSet "
-                 "WHERE InbredSet.Name = '{}' AND "
-                 "PublishFreeze.InbredSetId = InbredSet.Id "
-                 "ORDER BY PublishFreeze.CreateTime ASC")
-                .format(group)).fetchone()
 
+        elif type_name == "Genotypes":
+            cursor.execute(
+                ("SELECT InfoFiles.GN_AccesionId "
+                 "FROM InfoFiles, GenoFreeze, InbredSet "
+                 "WHERE InbredSet.Name = '{}' AND "
+                 "GenoFreeze.InbredSetId = InbredSet.Id AND "
+                 "InfoFiles.InfoPageName = GenoFreeze.ShortName "
+                 "ORDER BY GenoFreeze.CreateTime "
+                 "DESC").format(group))
+            results = cursor.fetchone()
             dataset_id = "None"
-            dataset_value = str(result[0])
-            dataset_text = str(result[1])
+            if bool(results):
+                dataset_id = str(results[0])
+
+            dataset_value = "%sGeno" % group
+            dataset_text = "%s Genotypes" % group
             datasets.append([dataset_id, dataset_value, dataset_text])
 
-    elif type_name == "Genotypes":
-        results = g.db.execute(
-            ("SELECT InfoFiles.GN_AccesionId "
-             "FROM InfoFiles, GenoFreeze, InbredSet "
-             "WHERE InbredSet.Name = '{}' AND "
-             "GenoFreeze.InbredSetId = InbredSet.Id AND "
-             "InfoFiles.InfoPageName = GenoFreeze.ShortName "
-             "ORDER BY GenoFreeze.CreateTime DESC").format(group)).fetchone()
-
-        dataset_id = "None"
-        if bool(results):
-            dataset_id = str(results[0])
-
-        dataset_value = "%sGeno" % group
-        dataset_text = "%s Genotypes" % group
-        datasets.append([dataset_id, dataset_value, dataset_text])
-
-    else:  # for mRNA expression/ProbeSet
-        results = g.db.execute(
-            ("SELECT ProbeSetFreeze.Id, ProbeSetFreeze.Name, "
-             "ProbeSetFreeze.FullName FROM ProbeSetFreeze, "
-             "ProbeFreeze, InbredSet, Tissue, Species WHERE "
-             "Species.Name = '{0}' AND Species.Id = "
-             "InbredSet.SpeciesId AND InbredSet.Name = '{1}' "
-             "AND ProbeSetFreeze.ProbeFreezeId = ProbeFreeze.Id "
-             "AND Tissue.Name = '{2}' AND ProbeFreeze.TissueId = "
-             "Tissue.Id AND ProbeFreeze.InbredSetId = InbredSet.Id "
-             "AND ProbeSetFreeze.public > 0 "
-             "ORDER BY -ProbeSetFreeze.OrderList DESC, ProbeSetFreeze.CreateTime DESC").format(species, group, type_name)).fetchall()
-
-        datasets = []
-        for dataset_info in results:
-            this_dataset_info = []
-            for info in dataset_info:
-                this_dataset_info.append(str(info))
-            datasets.append(this_dataset_info)
+        else:  # for mRNA expression/ProbeSet
+            cursor.execute(
+                ("SELECT ProbeSetFreeze.Id, ProbeSetFreeze.Name, "
+                 "ProbeSetFreeze.FullName FROM ProbeSetFreeze, "
+                 "ProbeFreeze, InbredSet, Tissue, Species WHERE "
+                 "Species.Name = '{0}' AND Species.Id = "
+                 "InbredSet.SpeciesId AND InbredSet.Name = '{1}' "
+                 "AND ProbeSetFreeze.ProbeFreezeId = ProbeFreeze.Id "
+                 "AND Tissue.Name = '{2}' AND ProbeFreeze.TissueId = "
+                 "Tissue.Id AND ProbeFreeze.InbredSetId = InbredSet.Id "
+                 "AND ProbeSetFreeze.public > 0 "
+                 "ORDER BY -ProbeSetFreeze.OrderList DESC, "
+                 "ProbeSetFreeze.CreateTime "
+                 "DESC").format(species, group, type_name))
+            results = cursor.fetchall()
+            datasets = []
+            for dataset_info in results:
+                this_dataset_info = []
+                for info in dataset_info:
+                    this_dataset_info.append(str(info))
+                datasets.append(this_dataset_info)
 
     return datasets
diff --git a/wqflask/wqflask/api/router.py b/wqflask/wqflask/api/router.py
index aec74c9e..a739e5a9 100644
--- a/wqflask/wqflask/api/router.py
+++ b/wqflask/wqflask/api/router.py
@@ -6,11 +6,13 @@ import csv
 import json
 import datetime
 import requests
+import MySQLdb
 
 from zipfile import ZipFile, ZIP_DEFLATED
 
 
 import flask
+from flask import current_app
 from flask import g
 from flask import request
 from flask import make_response
@@ -845,7 +847,11 @@ def get_genotypes(group_name, file_format="csv", dataset_name=None):
 
 @app.route("/api/v_{}/gen_dropdown".format(version), methods=("GET",))
 def gen_dropdown_menu():
-    results = gen_menu.gen_dropdown_json()
+    conn = MySQLdb.Connect(db=current_app.config.get("DB_NAME"),
+                           user=current_app.config.get("DB_USER"),
+                           passwd=current_app.config.get("DB_PASS"),
+                           host=current_app.config.get("DB_HOST"))
+    results = gen_menu.gen_dropdown_json(conn)
 
     if len(results) > 0:
         return flask.jsonify(results)
diff --git a/wqflask/wqflask/gsearch.py b/wqflask/wqflask/gsearch.py
index fb8bdc55..8f66f7e9 100644
--- a/wqflask/wqflask/gsearch.py
+++ b/wqflask/wqflask/gsearch.py
@@ -121,16 +121,14 @@ class GSearch:
                             continue
 
                     max_lrs_text = "N/A"
-                    if this_trait['locus_chr'] != None and this_trait['locus_mb'] != None:
-                        max_lrs_text = "Chr" + \
-                            str(this_trait['locus_chr']) + \
-                            ": " + str(this_trait['locus_mb'])
+                    if this_trait['locus_chr'] and this_trait['locus_mb']:
+                        max_lrs_text = f"Chr{str(this_trait['locus_chr'])}: {str(this_trait['locus_mb'])}"
                     this_trait['max_lrs_text'] = max_lrs_text
 
                     trait_list.append(this_trait)
 
             self.trait_count = len(trait_list)
-            self.trait_list = json.dumps(trait_list)
+            self.trait_list = trait_list
 
             self.header_fields = ['Index',
                                   'Record',
@@ -146,6 +144,22 @@ class GSearch:
                                   'Max LRS Location',
                                   'Additive Effect']
 
+            self.header_data_names = [
+                'index',
+                'name',
+                'species',
+                'group',
+                'tissue',
+                'dataset_fullname',
+                'symbol',
+                'description',
+                'location_repr',
+                'mean',
+                'LRS_score_repr',
+                'max_lrs_text',
+                'additive',
+            ]
+
         elif self.type == "phenotype":
             search_term = self.terms
             group_clause = ""
@@ -169,24 +183,23 @@ class GSearch:
                 PublishXRef.`LRS`,
                 PublishXRef.`additive`,
                 InbredSet.`InbredSetCode`,
-                PublishXRef.`mean`
-                FROM Species,InbredSet,PublishFreeze,PublishXRef,Phenotype,Publication
-                WHERE PublishXRef.`InbredSetId`=InbredSet.`Id`
-                AND PublishFreeze.`InbredSetId`=InbredSet.`Id`
-                AND InbredSet.`SpeciesId`=Species.`Id`
+                PublishXRef.`mean`,
+                PublishFreeze.Id,
+                Geno.Chr as geno_chr,
+                Geno.Mb as geno_mb 
+                FROM Species 
+                INNER JOIN InbredSet ON InbredSet.`SpeciesId`=Species.`Id` 
+                INNER JOIN PublishFreeze ON PublishFreeze.`InbredSetId`=InbredSet.`Id` 
+                INNER JOIN PublishXRef ON PublishXRef.`InbredSetId`=InbredSet.`Id` 
+                INNER JOIN Phenotype ON PublishXRef.`PhenotypeId`=Phenotype.`Id` 
+                INNER JOIN Publication ON PublishXRef.`PublicationId`=Publication.`Id` 
+                LEFT JOIN Geno ON PublishXRef.Locus = Geno.Name AND Geno.SpeciesId = Species.Id 
+                WHERE 
+                (
+                    (MATCH (Phenotype.Post_publication_description, Phenotype.Pre_publication_description, Phenotype.Pre_publication_abbreviation, Phenotype.Post_publication_abbreviation, Phenotype.Lab_code) AGAINST ('{1}' IN BOOLEAN MODE) )
+                    OR (MATCH (Publication.Abstract, Publication.Title, Publication.Authors) AGAINST ('{1}' IN BOOLEAN MODE) )
+                )
                 {0}
-                AND PublishXRef.`PhenotypeId`=Phenotype.`Id`
-                AND PublishXRef.`PublicationId`=Publication.`Id`
-                AND	  (Phenotype.Post_publication_description REGEXP "[[:<:]]{1}[[:>:]]"
-                    OR Phenotype.Pre_publication_description REGEXP "[[:<:]]{1}[[:>:]]"
-                    OR Phenotype.Pre_publication_abbreviation REGEXP "[[:<:]]{1}[[:>:]]"
-                    OR Phenotype.Post_publication_abbreviation REGEXP "[[:<:]]{1}[[:>:]]"
-                    OR Phenotype.Lab_code REGEXP "[[:<:]]{1}[[:>:]]"
-                    OR Publication.PubMed_ID REGEXP "[[:<:]]{1}[[:>:]]"
-                    OR Publication.Abstract REGEXP "[[:<:]]{1}[[:>:]]"
-                    OR Publication.Title REGEXP "[[:<:]]{1}[[:>:]]"
-                    OR Publication.Authors REGEXP "[[:<:]]{1}[[:>:]]"
-                    OR PublishXRef.Id REGEXP "[[:<:]]{1}[[:>:]]")
                 ORDER BY Species.`Name`, InbredSet.`Name`, PublishXRef.`Id`
                 LIMIT 6000
                 """.format(group_clause, search_term)
@@ -221,6 +234,9 @@ class GSearch:
                         this_trait['mean'] = f"{line[13]:.3f}"
                     else:
                         this_trait['mean'] = "N/A"
+                    this_trait['dataset_id'] = line[14]
+                    this_trait['locus_chr'] = line[15]
+                    this_trait['locus_mb'] = line[16]
                     this_trait['authors'] = line[7]
                     this_trait['year'] = line[8]
                     if this_trait['year'].isdigit():
@@ -241,32 +257,51 @@ class GSearch:
                     if line[11] != "" and line[11] != None:
                         this_trait['additive'] = '%.3f' % line[11]
 
+                    dataset_ob = SimpleNamespace(id=this_trait["dataset_id"], type="Publish", species=this_trait["species"])
+                    permissions = check_resource_availability(dataset_ob, this_trait['name'])
+                    if type(permissions['data']) is list:
+                        if "view" not in permissions['data']:
+                            continue
+                    else:
+                        if permissions['data'] == 'no-access':
+                            continue
+
                     this_trait['max_lrs_text'] = "N/A"
-                    trait_ob = create_trait(
-                        dataset_name=this_trait['dataset'], name=this_trait['name'], get_qtl_info=True, get_sample_info=False)
-                    if not trait_ob:
-                        continue
                     if this_trait['dataset'] == this_trait['group'] + "Publish":
                         try:
-                            if trait_ob.locus_chr != "" and trait_ob.locus_mb != "":
-                                this_trait['max_lrs_text'] = "Chr" + \
-                                    str(trait_ob.locus_chr) + \
-                                    ": " + str(trait_ob.locus_mb)
+                            if this_trait['locus_chr'] and this_trait['locus_mb']:
+                                this_trait['max_lrs_text'] = f"Chr{str(this_trait['locus_chr'])}: {str(this_trait['locus_mb'])}"
                         except:
                             this_trait['max_lrs_text'] = "N/A"
 
                     trait_list.append(this_trait)
 
             self.trait_count = len(trait_list)
-            self.trait_list = json.dumps(trait_list)
+            self.trait_list = trait_list
 
             self.header_fields = ['Index',
-                                  'Species',
-                                  'Group',
-                                  'Record',
-                                  'Description',
-                                  'Authors',
-                                  'Year',
-                                  'Max LRS',
-                                  'Max LRS Location',
-                                  'Additive Effect']
+                                'Species',
+                                'Group',
+                                'Record',
+                                'Description',
+                                'Authors',
+                                'Year',
+                                'Max LRS',
+                                'Max LRS Location',
+                                'Additive Effect']
+
+            self.header_data_names = [
+                'index',
+                'name',
+                'species',
+                'group',
+                'tissue',
+                'dataset_fullname',
+                'symbol',
+                'description',
+                'location_repr',
+                'mean',
+                'LRS_score_repr',
+                'max_lrs_text',
+                'additive',
+            ]
diff --git a/wqflask/wqflask/templates/gsearch_gene.html b/wqflask/wqflask/templates/gsearch_gene.html
index 6fd0abe8..48953d98 100644
--- a/wqflask/wqflask/templates/gsearch_gene.html
+++ b/wqflask/wqflask/templates/gsearch_gene.html
@@ -55,7 +55,15 @@
     <script language="javascript" type="text/javascript" src="/static/new/javascript/search_results.js"></script>
 
     <script type='text/javascript'>
-      var the_rows = {{ trait_list|safe }};
+      var getParams = function(url) {
+        let parser = document.createElement('a');
+        parser.href = url;
+        let params = parser.search.substring(1);
+        if(params.length > 0) {
+          return ('?'+params);
+        }
+        return params;
+      };
     </script>
 
     <script type="text/javascript" charset="utf-8">
@@ -142,7 +150,6 @@
                     $('td', row).eq(12).attr('data-export', $('td', row).eq(12).text());
                     $('td', row).eq(13).attr('data-export', $('td', row).eq(13).text());
                 },
-                'data': the_rows,
                 'columns': [
                     { 
                       'data': null,
@@ -237,11 +244,13 @@
                 'order': [[1, "asc" ]],
                 'sDom': "pitirp",
                 'autoWidth': true,
-                'iDisplayLength': 500,
                 'deferRender': false,
                 'paging': true,
                 'orderClasses': true,
                 'processing': true,
+                'iDisplayLength': 100,
+                'bServerSide': true,
+                'sAjaxSource': '/gsearch_table'+getParams(window.location.href),
                 'language': {
                   'loadingRecords': '&nbsp;',
                   'processing': 'Loading...'
diff --git a/wqflask/wqflask/templates/gsearch_pheno.html b/wqflask/wqflask/templates/gsearch_pheno.html
index 987b51a7..af9740ae 100644
--- a/wqflask/wqflask/templates/gsearch_pheno.html
+++ b/wqflask/wqflask/templates/gsearch_pheno.html
@@ -55,7 +55,15 @@
     <script language="javascript" type="text/javascript" src="/static/new/javascript/search_results.js"></script>
 
     <script type='text/javascript'>
-      var the_rows = {{ trait_list|safe }};
+      var getParams = function(url) {
+        let parser = document.createElement('a');
+        parser.href = url;
+        let params = parser.search.substring(1);
+        if(params.length > 0) {
+          return ('?'+params);
+        }
+        return params;
+      };
     </script>
 
     <script type="text/javascript" charset="utf-8">
@@ -130,7 +138,6 @@
                     $('td', row).eq(9).attr('data-export', $('td', row).eq(9).text());
                     $('td', row).eq(10).attr('data-export', $('td', row).eq(10).text());
                 },
-                'data': the_rows,
                 'columns': [
                     {
                       'data': null,
@@ -241,10 +248,12 @@
                 'sDom': "pitirp",
                 'autoWidth': false,
                 'deferRender': false,
-                'iDisplayLength': 500,
                 'paging': true,
                 'orderClasses': true,
                 'processing': true,
+                'iDisplayLength': 100,
+                'bServerSide': true,
+                'sAjaxSource': '/gsearch_table'+getParams(window.location.href),
                 'language': {
                   'loadingRecords': '&nbsp;',
                   'processing': 'Loading...'
diff --git a/wqflask/wqflask/views.py b/wqflask/wqflask/views.py
index 276d3019..d2ede70f 100644
--- a/wqflask/wqflask/views.py
+++ b/wqflask/wqflask/views.py
@@ -279,6 +279,19 @@ def gsearchact():
     elif type == "phenotype":
         return render_template("gsearch_pheno.html", **result)
 
+@app.route("/gsearch_table", methods=('GET',))
+def gsearchtable():
+    logger.info(request.url)
+
+    gsearch_table_data = GSearch(request.args)
+    current_page = server_side.ServerSideTable(
+        gsearch_table_data.trait_count,
+        gsearch_table_data.trait_list,
+        gsearch_table_data.header_data_names,
+        request.args,
+    ).get_page()
+
+    return flask.jsonify(current_page)
 
 @app.route("/gsearch_updating", methods=('POST',))
 def gsearch_updating():