series.sql: make diffstart/diffend optional

We also show the impact on the `insertion_dates` call with
from/to_value_date restrictions.
3 files changed, 59 insertions(+), 11 deletions(-)

M test/test_tsio.py
M tshistory/migrate.py
M tshistory/series.sql
M test/test_tsio.py +52 -0
@@ 887,6 887,58 @@ 2024-04-05 00:00:00+00:00  2024-04-01 00
     assert len(revs) == 5
 
 
+def test_insertion_dates_without_diffs(engine, tsh):
+    if tsh.namespace != 'tsh':
+        return
+
+    for i in range(3):
+        ts = pd.Series(
+            [i],
+            index=pd.date_range(
+                utcdt(2024, 1, i+1),
+                freq='d',
+                periods=1
+            )
+        )
+        tsh.update(
+            engine,
+            ts,
+            'hist-no-diff',
+            'Babar',
+            insertion_date=utcdt(2024, 1, i+1)
+        )
+
+    idates = tsh.insertion_dates(
+        engine,
+        'hist-no-diff',
+        from_value_date=utcdt(2024, 1, 2),
+        to_value_date=utcdt(2024, 1, 2)
+    )
+    assert idates == [
+        pd.Timestamp('2024-01-02 00:00:00+0000', tz='UTC')
+    ]
+
+    # now, erase one diffstart / diffend
+    with engine.begin() as cn:
+        cn.cache = {'series_tablename': {}}
+        tablename = tsh._series_to_tablename(cn, 'hist-no-diff')
+        # engine.execute(f'select id, diffstart from "tsh.revision"."{tablename}"').fetchall()
+
+        cn.execute(
+            f'update "tsh.revision"."{tablename}" '
+            f'set diffstart = NULL,'
+            '     diffend = NULL'
+        )
+
+    idates = tsh.insertion_dates(
+        engine,
+        'hist-no-diff',
+        from_value_date=utcdt(2024, 1, 2),
+        to_value_date=utcdt(2024, 1, 2)
+    )
+    assert idates == []
+
+
 def test_first_latest_insertion_date(engine, tsh):
     name = 'test-f-l-idate'
     for i in range(3):

          
M tshistory/migrate.py +5 -9
@@ 173,6 173,10 @@ def migrate_add_diffstart_diffend(engine
     from tshistory import util
     print(f'add columns `diffstart` and `diffend` to {namespace}.revision')
 
+    if interactive:
+        if yesno('Defer data migration to a task ? [y/n] '):
+            return
+
     def migrated(cn, tablename):
         sql = (
             f"select exists (select 1 "

          
@@ 206,15 210,7 @@ def migrate_add_diffstart_diffend(engine
         return True
 
     def finalizeattributes(cn, tablename):
-        # put the not null constraints
-        cn.execute(
-            f'alter table "{namespace}.revision"."{tablename}" '
-            f'alter column diffstart set not null'
-        )
-        cn.execute(
-            f'alter table "{namespace}.revision"."{tablename}" '
-            f'alter column diffend set not null'
-        )
+        # drop the not null constraints for tsstart/tsend
         cn.execute(
             f'alter table "{namespace}.revision"."{tablename}" '
             f'alter column tsstart drop not null'

          
M tshistory/series.sql +2 -2
@@ 15,8 15,8 @@ create table "{namespace}.revision"."{ta
   id serial primary key,
   tsstart timestamp, -- whole series index min
   tsend timestamp,   -- whole series index max
-  diffstart timestamptz not null, -- diff index min
-  diffend timestamptz not null,   -- diff index min
+  diffstart timestamptz, -- diff index min
+  diffend timestamptz,   -- diff index min
   snapshot integer references "{namespace}.snapshot"."{tablename}"(id),
   author text not null,
   insertion_date timestamptz not null,