From fa9f31779aa97e3cac2e2be7816b50b30a5dc393 Mon Sep 17 00:00:00 2001
From: Emmanuel Cazenave <ecazenave@entrouvert.com>
Date: Fri, 22 Feb 2019 15:35:04 +0100
Subject: [PATCH 2/2] keep data form previous run in labeled table (#30752)

---
 tests/test_wcs.py  | 41 +++++++++++++++++++++++++++++++++++
 wcs_olap/feeder.py | 53 +++++++++++++++++++++++++++++++++++-----------
 2 files changed, 82 insertions(+), 12 deletions(-)

diff --git a/tests/test_wcs.py b/tests/test_wcs.py
index d9d2109..b89f74a 100644
--- a/tests/test_wcs.py
+++ b/tests/test_wcs.py
@@ -6,6 +6,8 @@ import requests
 import pathlib2
 import mock
 
+import utils
+
 
 def test_wcs_fixture(wcs, postgres_db, tmpdir, olap_cmd, caplog):
     olap_cmd()
@@ -113,3 +115,42 @@ def test_requests_not_json(wcs, postgres_db, tmpdir, olap_cmd, caplog):
         with pytest.raises(SystemExit):
             olap_cmd(no_log_errors=False)
     assert 'Invalid JSON content' in caplog.text
+
+
+def test_dimension_stability(wcs, wcs_dir, postgres_db, tmpdir, olap_cmd, caplog):
+    olap_cmd()
+
+    with postgres_db.conn() as conn:
+        with conn.cursor() as c:
+            c.execute('SET search_path TO \'olap\'')
+            c.execute('SELECT * FROM formdata_demande_field_item ORDER BY id')
+            refs = c.fetchall()
+            assert len(refs) == 3
+
+    # Change an item of the field
+    script = u"""
+from wcs.formdef import FormDef
+
+formdef = FormDef.get_by_urlname('demande')
+for field in formdef.fields:
+    if field.label == '2nd field':
+        ref_field = field
+        break
+ref_field.items = ['foo', 'bar', 'bazouka']
+formdef.store()
+"""
+    utils.run_wcs_script(wcs_dir, script, 'toto')
+    olap_cmd()
+
+    # We expect to find in the new dimension table
+    # the same  records as before (including the one of the item that disappeared)
+    # plus the new item
+    with postgres_db.conn() as conn:
+        with conn.cursor() as c:
+            c.execute('SET search_path TO \'olap\'')
+            c.execute('SELECT * FROM formdata_demande_field_item ORDER BY id')
+            new_refs = c.fetchall()
+            assert len(new_refs) == 4
+    for ref in refs:
+        assert ref in new_refs
+    assert new_refs[-1][1] == 'bazouka'
diff --git a/wcs_olap/feeder.py b/wcs_olap/feeder.py
index 179d298..47562fe 100644
--- a/wcs_olap/feeder.py
+++ b/wcs_olap/feeder.py
@@ -340,19 +340,48 @@ CREATE TABLE public.dates AS (SELECT
             self.ex('COMMENT ON TABLE %s IS %%s' % name, vars=(comment,))
 
     def create_labeled_table(self, name, labels, serial=False, comment=None):
-        if serial:
-            id_type = 'serial primary key'
+
+        query = """SELECT EXISTS (SELECT 1 FROM information_schema.tables
+        WHERE  table_schema = '{schema}' AND table_name = '%s')""" % name
+        self.ex(query)
+        table_exists = self.cur.fetchone()[0]
+
+        if table_exists:
+            self.ex(
+                'CREATE TABLE {schema_temp}.%(name)s (LIKE {schema}.%(name)s INCLUDING ALL)' %
+                {'name': name}
+            )
+            self.ex(
+                'INSERT INTO {schema_temp}.%(name)s select * FROM {schema}.%(name)s' %
+                {'name': name}
+            )
+            for _id, _label in labels:
+                self.ex("SELECT * FROM %s WHERE label = '%s'" % (name, _label))
+                if self.cur.fetchone() is None:
+                    self.ex(
+                        "SELECT nextval(pg_get_serial_sequence('%s', 'id')) AS new_id;" % name)
+                    res = self.cur.fetchone()[0]
+                    if res is None:
+                        self.ex('SELECT MAX(id) FROM %s' % name)
+                        next_id = self.cur.fetchone()[0] + 1
+                    else:
+                        next_id = res
+                    values = self.cur.mogrify('(%s, %s)', [next_id, _label])
+                    self.ex('INSERT INTO %s (id, label) VALUES %s' % (str(name), values))
         else:
-            id_type = 'smallint primary key'
-        self.create_table(name,
-                          [
-                              ['id', id_type],
-                              ['label', 'varchar']
-                          ], comment=comment)
-        values = ', '.join(self.cur.mogrify('(%s, %s)', [_id, _label]) for _id, _label in labels)
-        if not values:
-            return
-        self.ex('INSERT INTO %s (id, label) VALUES %s' % (str(name), values))
+            if serial:
+                id_type = 'serial primary key'
+            else:
+                id_type = 'smallint primary key'
+            self.create_table(name,
+                              [
+                                  ['id', id_type],
+                                  ['label', 'varchar']
+                              ], comment=comment)
+            values = ', '.join(self.cur.mogrify('(%s, %s)', [_id, _label]) for _id, _label in labels)
+            if not values:
+                return
+            self.ex('INSERT INTO %s (id, label) VALUES %s' % (str(name), values))
 
     def tpl(self, o, ctx=None):
         ctx = ctx or {}
-- 
2.20.1

